在现代 Web 架构中,CDN(如 Cloudflare)或反向代理(如 WAF、负载均衡)已是标配。它们在提速和防攻击的同时,也带来了一个副作用:源站 Nginx 看到的请求 IP 全变成了代理服务器的 IP。
这会导致:
- 安全失效:基于 IP 的限流(Rate Limiting)或黑名单完全失效。
- 日志失真:无法统计用户真实的地理位置分布。
- 业务错误:如果代码逻辑依赖 IP,会导致判断错误。
一、 核心原理:X-Forwarded-For 与 Real IP 模块
当请求经过代理时,代理服务器会将原始 IP 放入 HTTP 头部(通常是 X-Forwarded-For),格式如下:
X-Forwarded-For: 客户端真实IP, 代理1的IP, 代理2的IP...
Nginx 的 ngx_http_realip_module 模块作用就是:通过信任指定的代理 IP,从头部信息中把 $remote_addr 变量“修正”为真正的客户端 IP。
注意:请先运行
nginx -V检查输出中是否包含--with-http_realip_module。
二、 解决方案:三步搞定 Nginx 配置
1. 定义信任池与提取规则
在 http 或 server 段中配置。**绝对不要使用 0.0.0.0/0**,因为这允许攻击者通过伪造 Header 随意欺骗你的服务器 IP 记录。
# 1. 设置信任的代理服务器 IP(以 Cloudflare 为例)set_real_ip_from 173.245.48.0/20;set_real_ip_from 103.21.244.0/22;# ... 此处省略其他段
# 2. 指定从哪个 Header 获取真实 IPreal_ip_header X-Forwarded-For;
# 3. 递归查找:排除掉信任池里的所有代理 IP,剩下的最后一个才是真实用户 IPreal_ip_recursive on;2. 反向代理给后端(若有二级代理)
如果你的 Nginx 后面还有 Web 应用(如 PHP-FPM 或 Node.js),需要继续透传:
location / { proxy_set_header Host $host; # 此时 $remote_addr 已经是 real_ip 模块修正过的真实用户 IP proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}三、 Cloudflare 特殊处理方案
如果你使用 Cloudflare,推荐直接使用其独有的 CF-Connecting-IP 头部,这比 X-Forwarded-For 更简洁且不易被篡改。
1. 自动化更新 Cloudflare IP 脚本
由于 Cloudflare 的 IP 段会定期更新,手动维护 set_real_ip_from 非常麻烦。建议创建一个自动加载脚本:
# 生成配置文件curl -s https://www.cloudflare.com/ips-v4 | sed 's|^|set_real_ip_from |; s|$|;|' > /etc/nginx/conf.d/cloudflare_ips.confcurl -s https://www.cloudflare.com/ips-v6 | sed 's|^|set_real_ip_from |; s|$|;|' >> /etc/nginx/conf.d/cloudflare_ips.conf2. Nginx 调用
http { include conf.d/cloudflare_ips.conf; real_ip_header CF-Connecting-IP; # ...}四、 进阶:如何验证配置是否生效?
1. 测试配置语法
nginx -t2. 模拟请求测试
即使没有 CDN,你也可以在本地通过 curl 模拟代理请求来测试 Nginx 是否正确提取:
# 假设你的 Nginx 信任 127.0.0.1curl -H "X-Forwarded-For: 1.1.1.1" http://localhost/test查看日志,如果显示的 IP 是 1.1.1.1 而不是 127.0.0.1,说明 real_ip 模块工作正常。
五、 其他注意事项与安全风险
- 安全警告:永远不要信任不受控的 IP 地址。如果你的
set_real_ip_from包含了恶意用户的 IP,他就可以通过在请求头中加入X-Forwarded-For: 8.8.8.8来伪装成 Google 管理员。 - 日志格式优化:建议在
log_format中显式包含$http_x_forwarded_for,以便在出问题时对比原始头部信息。 - 多级代理顺序:
real_ip_recursive on会从右向左排除信任 IP。务必确保你的代理链条完整且都在信任列表中。
总结
解决获取不到真实 IP 的核心在于:信任代理节点、正确选择 Header、递归排除代理路径。这不仅是为了日志好看,更是后端业务逻辑和安全防护的先决条件。