871 字
4 分钟
彻底解决 CDN/反代后 Nginx 获取不到真实 IP 的实战指南

在现代 Web 架构中,CDN(如 Cloudflare)或反向代理(如 WAF、负载均衡)已是标配。它们在提速和防攻击的同时,也带来了一个副作用:源站 Nginx 看到的请求 IP 全变成了代理服务器的 IP

这会导致:

  1. 安全失效:基于 IP 的限流(Rate Limiting)或黑名单完全失效。
  2. 日志失真:无法统计用户真实的地理位置分布。
  3. 业务错误:如果代码逻辑依赖 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. 定义信任池与提取规则#

httpserver 段中配置。**绝对不要使用 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 获取真实 IP
real_ip_header X-Forwarded-For;
# 3. 递归查找:排除掉信任池里的所有代理 IP,剩下的最后一个才是真实用户 IP
real_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 非常麻烦。建议创建一个自动加载脚本:

Terminal window
# 生成配置文件
curl -s https://www.cloudflare.com/ips-v4 | sed 's|^|set_real_ip_from |; s|$|;|' > /etc/nginx/conf.d/cloudflare_ips.conf
curl -s https://www.cloudflare.com/ips-v6 | sed 's|^|set_real_ip_from |; s|$|;|' >> /etc/nginx/conf.d/cloudflare_ips.conf

2. Nginx 调用#

http {
include conf.d/cloudflare_ips.conf;
real_ip_header CF-Connecting-IP;
# ...
}

四、 进阶:如何验证配置是否生效?#

1. 测试配置语法#

Terminal window
nginx -t

2. 模拟请求测试#

即使没有 CDN,你也可以在本地通过 curl 模拟代理请求来测试 Nginx 是否正确提取:

Terminal window
# 假设你的 Nginx 信任 127.0.0.1
curl -H "X-Forwarded-For: 1.1.1.1" http://localhost/test

查看日志,如果显示的 IP 是 1.1.1.1 而不是 127.0.0.1,说明 real_ip 模块工作正常。


五、 其他注意事项与安全风险#

  1. 安全警告:永远不要信任不受控的 IP 地址。如果你的 set_real_ip_from 包含了恶意用户的 IP,他就可以通过在请求头中加入 X-Forwarded-For: 8.8.8.8 来伪装成 Google 管理员。
  2. 日志格式优化:建议在 log_format 中显式包含 $http_x_forwarded_for,以便在出问题时对比原始头部信息。
  3. 多级代理顺序real_ip_recursive on 会从右向左排除信任 IP。务必确保你的代理链条完整且都在信任列表中。

总结#

解决获取不到真实 IP 的核心在于:信任代理节点、正确选择 Header、递归排除代理路径。这不仅是为了日志好看,更是后端业务逻辑和安全防护的先决条件。

彻底解决 CDN/反代后 Nginx 获取不到真实 IP 的实战指南
https://sw.rscclub.website/posts/zsip/
作者
杨月昌
发布于
2021-01-19
许可协议
CC BY-NC-SA 4.0