最近要给网站上 CDN 于是折腾了下在 NGINX 部分获取客户端真实 IP 的方案。

嘛… 意想不到的简单就是…

安装 realip 模块

如果是 Debian/Ubuntu 系统,直接安装 nginx-extras 这个包即可。包含了很多有用的模块,不需要再自己编译。

如果是其他发行版,且没有提供额外模块的包的话,需要自己编译 NGINX。编译参数加 --with-http_realip_module 即可。

获得前端服务器地址

常见的 CDN 前端 IP 都可以从 CDN 提供商处获得,例如 CloudFlare 的 IP 地址段在这里

如果需要找到 Google Cloud Platform 的 IP 地址段,可以使用 Google 提供的 TXT 记录查询。

1
$ dig @8.8.8.8 _cloud-netblocks.googleusercontent.com TXT

获得记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
; <<>> DiG 9.11.0-P2 <<>> @8.8.8.8 _cloud-netblocks.googleusercontent.com TXT
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 42732
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;_cloud-netblocks.googleusercontent.com. IN TXT

;; ANSWER SECTION:
_cloud-netblocks.googleusercontent.com. 3599 IN TXT "v=spf1 include:_cloud-netblocks1.googleusercontent.com include:_cloud-netblocks2.googleusercontent.com include:_cloud-netblocks3.googleusercontent.com include:_cloud-netblocks4.googleusercontent.com include:_cloud-netblocks5.googleusercontent.com ?all"

;; Query time: 51 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Wed Feb 08 20:31:29 JST 2017
;; MSG SIZE rcvd: 331

这里面的 _cloud-netblocks1.googleusercontent.com 等地址即是用于保存 GCP IP 段的地址。继续查询:

1
dig @8.8.8.8 _cloud-netblocks1.googleusercontent.com TXT

获得记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
; <<>> DiG 9.11.0-P2 <<>> @8.8.8.8 _cloud-netblocks1.googleusercontent.com TXT
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 22867
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;_cloud-netblocks1.googleusercontent.com. IN TXT

;; ANSWER SECTION:
_cloud-netblocks1.googleusercontent.com. 3599 IN TXT "v=spf1 ip4:8.34.208.0/20 ip4:8.35.192.0/21 ip4:8.35.200.0/23 ip4:108.59.80.0/20 ip4:108.170.192.0/20 ip4:108.170.208.0/21 ip4:108.170.216.0/22 ip4:108.170.220.0/23 ip4:108.170.222.0/24 ?all"

;; Query time: 55 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Wed Feb 08 20:32:39 JST 2017
;; MSG SIZE rcvd: 270

于是得到了一堆 IP 地址。

设置 RealIP 模块

文件 /etc/nginx/snippets/realip.conf,请注意这个位置在其他发行版未必存在,放在 NGINX 配置目录下即可。

1
2
3
4
set_real_ip_from  192.168.1.0/24;
set_real_ip_from 192.168.2.1;
set_real_ip_from 2001:0db8::/32;
real_ip_header X-Forwarded-For;

然后在 vhost 配置文件中引用这个配置。

1
include snippets/realip.conf;

搞定,重启 NGINX 即可获得客户端真实 IP。

Note:

GCP 的 X-Forwarded-For 的客户端 IP 在第一个 , 的前面,所以一般需要 split(',')[0]