背景
Nginx对每个模块都有说明文档,可参考:https://nginx.org/en/docs/
当请求被代理后,真实客户端相对服务器被隐藏,即服务端无法判断HTTP消息来源。
如上图所示,IP分别为100.100.100.1和100.100.100.2的两个客户端向服务器200.200.200.200发起http请求,经过100.100.100.100代理后,HTTP消息到达200.200.200.200服务器时,消息一致;此时,无法区分消息来自100.100.100.1或100.100.100.2.
可通过将客户端的IP添加入HTTP消息解决上述问题,可在消息头中添加字段。
此时,服务器从http头域提取RealIp字段即可获取客户端IP信息。
Nginx中的入http_realip_module模块提供了上述能力。
1.编译和安装
#下载资源
wget http://nginx.org/download/nginx-1.26.0.tar.gz# 解压资源
tar -zxvf nginx-1.26.0.tar.gz# 编译nginx
cd nginx-1.26.0/
./configure --prefix=/usr/local/ewen/nginx --with-http_realip_module
./make# 安装nginx
./make install
说明:Nginx默认不会携带http_realip_module模块,因此编译需要使用通过--with-http_realip_module
手动指定引入该模块。
2.使用方式
需要在代理和服务器分别进行配置,以实现realIp功能。
2.1 代理配置
说明:有多级代理时,中间代理也需要进行配置
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
将客户端/上一级代理的IP添加到X-Forwarded-For请求头中,是一个不断添加的过程;如下图所示:
2.2 服务器配置
服务器涉及的配置项包括set_real_ip_from配置、real_ip_header配置、 real_ip_recursive配置,可以配置在http块、server块、location块中。
[1] real_ip_header
指定获取real_ip的字段,即从http消息头域的哪个字段中获取,此时固定为X-Forwarded-For,如下所示:
real_ip_header X-Forwarded-For;
[2] set_real_ip_from
设置信任的IP,即用于设置中间代理服务器的IP。
上图中需要设置3个IP, 如下所示:
set_real_ip_from 2.2.2.2;
set_real_ip_from 3.3.3.3;
set_real_ip_from 4.4.4.4;
说明:可以设置IP,也可以设置IP段,如set_real_ip_from 4.4.4.4/24
.
[3] real_ip_recursive
可以配置为开(on)或者关(off).
配置为on时: 将根据set_real_ip_from设置的受信任的IP,对X-Forwarded-For从右至左递归排除,直到得到右侧第一个非受信任的IP地址,将其设置为realIp。
配置为off时: 如果没有使用set_real_ip_from设置上一级代理为受信任IP,则将上一级代理的IP设置为realIp; 如果使用set_real_ip_from排除上一级代理后,则获取X-Forwarded-For最右侧一位作为realIp.
即real_ip_recursive关闭后,表示不支持多级代理。
2.3 服务器获取realip
服务器通过$remote_addr变量获取realip. 具体使用方式在下一章节结合案例进行介绍。
2.4 X-Real-IP
除了使用上述X_Fowarded-For逐层追加IP外,还可使用X-Real-IP:在第一层(靠近客户端侧)添加头域,其他代理层透传,不需要额外设置, 如下图所示:
[1] 第一级代理
在靠近客户端的第一级代理中添加配置:
proxy_set_header X-Real-IP $remote_addr;
[2] 服务器配置
real_ip_header X-Real-IP;# 添加相对服务器上一级代理的IP地址
set_real_ip_from 4.4.4.4;
[3] 服务器使用realIp
服务器通过$remote_addr变量获取realIp. 具体使用方式在下一章节结合案例进行介绍。
3.案例
3.1 X-Forwarded-For
架构图和配置分别如下所示:
#171 agent
server {listen 8001;server_name localhost;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;location /query {proxy_pass http://192.168.100.172:8002;}
}#172 agent
server {listen 8002;server_name localhost;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;location /query {proxy_pass http://192.168.100.173:8003;}
}#173 agent
server {listen 8003;server_name localhost;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;location /query {proxy_pass http://192.168.100.174:8004;}
}#174 server
server {listen 8004;server_name localhost;real_ip_header X-Forwarded-For;real_ip_recursive on;set_real_ip_from 192.168.100.173;set_real_ip_from 192.168.100.172;set_real_ip_from 192.168.100.171;location /query {return 200 "Msg from 192.168.100.174:8004, request from $remote_addr";}
}
在客户端(192.168.100.100)上发送http://192.168.100.171:8001/query,得到的结果如下:
Msg from 192.168.100.174:8004, request from 192.168.100.100
在174服务器上抓包结果如下所示:
GET /query HTTP/1.0
X-Forwarded-For: 192.168.100.100, 192.168.100.171, 192.168.100.172
Host: 192.168.100.174:8004
Connection: close
User-Agent: PostmanRuntime/7.26.8
Accept: */*
Postman-Token: b3e9111f-a199-4bed-95bd-9115c0d4cc3f
Accept-Encoding: gzip, deflate, brHTTP/1.1 200 OK
Server: nginx/1.26.0
Date: Fri, 20 Jul 2024 12:48:37 GMT
Content-Type: application/octet-stream
Content-Length: 31
Connection: closeMsg from 192.168.100.174:8004, request from 192.168.100.100
3.2 X-Real-IP
使用X-Real-IP时,对配置进行以下修改:
#171 agent
server {listen 8001;server_name localhost;proxy_set_header X-Real-IP $remote_addr;location /query {proxy_pass http://192.168.100.172:8002;}
}#172 agent
server {listen 8002;server_name localhost;location /query {proxy_pass http://192.168.100.173:8003;}
}#173 agent
server {listen 8003;server_name localhost;location /query {proxy_pass http://192.168.100.174:8004;}
}#174 server
server {listen 8004;server_name localhost;real_ip_header X-Real-IP;set_real_ip_from 192.168.100.173;location /query {return 200 "Msg from 192.168.100.174:8004, request from $remote_addr";}
}
在客户端(192.168.100.100)上发送http://192.168.100.171:8001/query,得到的结果如下:
Msg from 192.168.100.174:8004, request from 192.168.100.100
在174服务器上抓包结果如下所示:
GET /query HTTP/1.0
Host: 192.168.100.174:8004
Connection: close
X-Real-IP: 192.168.100.100
User-Agent: PostmanRuntime/7.26.8
Accept: */*
Postman-Token: 953bfb0c-e553-4a67-a498-ffb659b9071f
Accept-Encoding: gzip, deflate, brHTTP/1.1 200 OK
Server: nginx/1.26.0
Date: Fri, 20 Jul 2024 12:53:53 GMT
Content-Type: application/octet-stream
Content-Length: 31
Connection: closeMsg from 192.168.100.174:8004, request from 192.168.100.100