我們訪問互聯網上的服務時,大多數時,客戶端並不是直接訪問到服務端的,而是客戶端首先請求到反向代理,反向代理再轉發到服務端實現服務訪問,通過反向代理實現路由/負載均衡等策略。這樣在服務端拿到的客戶端IP將是反向代理IP,而不是真實客戶端IP,因此需要想辦法來獲取到真實客戶端IP
# 客戶端訪問服務端的數據流走向
Client(172.25.0.1) --> ADSL( 192.168.0.1) --> cdn(10.0.0.1) --> SLB(反向代理)11.0.0.1 --> server(nginx)12.0.0.1
可以看出,服務端根本獲取不到真實的客戶端ip,只能獲取到上一層服務的ip,那么nginx怎樣才能獲取到真實的ip呢?
1.用一台服務器模擬實現獲取本機ip
源碼編譯,添加一個模塊,獲取real ip
[root@base1 ~]# tar zxf nginx-1.14.2.tar.gz [root@base1 ~]# yum install -y gcc pcre-devel zlib-devel # 這是編譯nginx的依賴包 [root@base1 ~]# cd nginx-1.14.2 [root@base1 nginx-1.14.2]# make [root@base1 nginx-1.14.2]# ./configure --prefix=/usr/local/nginx --with-http_realip_module # 添加了一個獲取realip的模塊 [root@base1 nginx-1.14.2]# make && make install [root@base1 nginx-1.14.2]# nginx -V # 查看編譯參數
[root@base1 nginx-1.14.2]# cd /usr/local/nginx/conf/ [root@base1 conf]# vim nginx.conf # 添加虛擬主機 server { listen 80; server_name base1.westos.org; location / { return 200; } }
[root@base1 conf]# nginx #開啟nginx服務 [root@base1 conf]# nginx -s reload [root@base1 conf]# vim /etc/hosts #添加域名 172.25.78.11 base1 base1.westos.org
[root@base1 conf]# curl -I base1.westos.org #測試
# 當檢測成功時,讓回應real ip
[root@base1 conf]# vim nginx.conf server { listen 80; server_name base1.westos.org; location / { return 200 "client real ip: $remote_addr\n"; # $remote_addr 代表客戶端真實IP } }
[root@base1 conf]# nginx -s reload #平滑重啟nginx
[root@base1 conf]# curl base1.westos.org #測試
# 從X-Forwarded-For中獲取到真實客戶端IP
[root@base1 conf]# vim nginx.conf server { listen 80; server_name base1.westos.org; # 添加域名 set_real_ip_from 172.25.78.11; # 真實服務器上一級代理的IP地址或者IP段,可以寫多行 real_ip_header X-Forwarded-For; # 告知Nginx真實客戶端IP從哪個請求頭獲取 real_ip_recursive off; # 是否遞歸解析,off表示默認從最后一個地址開始解析 location / { return 200 "client real ip: $remote_addr\n"; } }
[root@base1 conf]# nginx -s reload
[root@base1 conf]# curl -H "X-Forwarded-For:1.1.1.1,172.25.78.11" base1.westos.org #給X-Forwarded-For中添加ip,從而獲取ip 172.25.78.11
# 修改配置文件里的參數real_ip_recursive 為on
[root@base1 conf]# vim nginx.conf real_ip_recursive on; # 從前往后依次遞歸獲取ip [root@base1 conf]# nginx -s reload
[root@base1 conf]# curl -H "X-Forwarded-For:1.1.1.1,172.25.78.11" base1.westos.org #測試
以上操作僅僅實現了獲取本機ip和使用X-Forwarded-For的功能,現在我們來模擬實際生產中在有反向代理的阻礙下獲取真實客戶端ip,這里我們用一個反向代理來模擬
base1 : 后端服務器
base2 : nginx反向代理服務器
# 配置反向代理服務器
[root@base2 ~]# yum install -y gcc pcre-devel zlib-devel [root@base2 ~]# tar zxf nginx-1.14.2.tar.gz [root@base2 ~]# cd nginx-1.14.2 [root@base2 nginx-1.14.2]# vim auto/cc/gcc 171 # debug 172 #CFLAGS="$CFLAGS -g" [root@base2 nginx-1.14.2]# ./configure --prefix=/usr/local/nginx/ --with-http_realip_module [root@base2 nginx-1.14.2]# make && make install [root@base2 nginx-1.14.2]# cd /usr/local/nginx/conf/ server { listen 80; location / { proxy_set_header X-Real-IP $remote_addr; # 存放用戶的真實ip proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 每經過一個反向代理,就會把反向代理IP存放在X-Forwarded-For里 proxy_pass http://172.25.78.11:80; } } [root@base2 conf]# ln -s /usr/local/nginx/sbin/nginx /sbin [root@base2 conf]# nginx [root@base2 conf]# nginx -s reload
# 配置服務端
[root@base1 conf]# vim nginx.conf server { listen 80; server_name base1.westos.org; #域名 set_real_ip_from 172.25.78.0/24; real_ip_header X-Forwarded-For; real_ip_recursive on; location / { root /web; # 指定發布目錄 index index.html index.htm; } } [root@base1 conf]# nginx -s reload [root@base1 conf]# mkdir /web [root@base1 conf]# vim /web/index.html www.westos.org
# 客戶端測試
[root@foundation78 Desktop]# vim /etc/hosts 172.25.78.11 base1 base1.westos.org [root@foundation78 Desktop]# curl base1.westos.org www.westos.org
# 服務端查看日志
[root@base1 conf]# cat /usr/local/nginx/logs/access.log # 通過日志可以直接查看到客戶端真實ip
總結:
1.使用realip模塊后,$remote_addr輸出結果為真實客戶端IP,可以使用$realip_remote_addr獲取最后一個反向代理的IP;
2.real_ip_headerX-Forwarded-For:告知Nginx真實客戶端IP從哪個請求頭獲取;
3.set_real_ip_from 172.25.78.0/24:告知Nginx哪些是反向代理IP,即排除后剩下的就是真實客戶端IP
4.real_ip_recursive on:是否遞歸解析,當real_ip_recursive配置為off時,Nginx會把real_ip_header指定的請求頭中的最后一個IP作為真實客戶端IP;
當real_ip_recursive配置為on時,Nginx會遞歸解析real_ip_header指定的請求頭,最后一個不匹配set_real_ip_from的IP作為真實客戶端IP。