真实客户端ip准确传递需全链路透传x-forwarded-for并由最后一层nginx用realip模块校验:首层用$remote_addr初始化,后续用$proxy_add_x_forwarded_for追加;最后配置set_real_ip_from、real_ip_header x-forwarded-for和real_ip_recursive on,后端读x-real-ip或已修正的remote_addr。

要让真实客户端 IP 在 Nginx 多级代理链中准确传到最终后端,核心不是“加头”,而是建立一条可信、可验证、不中断的传递路径。漏掉任一环节——比如某层没透传 X-Forwarded-For,或最后一层没启用 realip 校验——IP 就会失真。
每一级代理都必须透传 X-Forwarded-For
这是全链路还原的基础,所有中间层(CDN、WAF、LB、网关)都要确保该头完整延续:
- 首层代理(直连公网或 CDN)用
proxy_set_header X-Forwarded-For $remote_addr;初始化,写入用户真实 IP - 后续每一层统一用
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;——它自动在已有值末尾追加本层看到的$remote_addr,形成类似1.1.1.1, 10.0.0.5, 10.0.0.6的格式 - 禁止清空、覆盖、手动拼接
X-Forwarded-For;任何一层缺失,链路即断裂
最后一层 Nginx 必须启用 realip 模块校验
仅靠读 X-Forwarded-For 是不安全的,攻击者可伪造。必须由最终接入的 Nginx 完成可信剥离:
- 确认编译时已启用
--with-http_realip_module - 在
http、server或location块中配置可信代理段:set_real_ip_from 10.0.0.0/8; set_real_ip_from 172.16.0.0/12; set_real_ip_from 192.168.0.0/16; set_real_ip_from 173.245.48.0/20; # Cloudflare 回源段
(按实际代理出口 IP 精确填写,不建议用宽泛范围)
- 指定解析来源:
real_ip_header X-Forwarded-For; - 开启递归解析:
real_ip_recursive on;—— Nginx 将从右往左跳过所有可信 IP,取第一个非可信地址作为真实客户端 IP,并自动更新$remote_addr
后端应用应读取经 realip 修正后的值
应用代码无需再解析 X-Forwarded-For 字符串,直接使用已校验的结果:
- 优先读
X-Real-IP(由 Nginx 注入,等价于修正后的$remote_addr) - 若框架支持,也可直接用
request.getRemoteAddr()(如 PHP 的$_SERVER['REMOTE_ADDR']、Java 的HttpServletRequest.getRemoteAddr()),前提是realip已生效 - 禁用“取
X-Forwarded-For第一个 IP”的简单写法,否则可能拿到 CDN 或中间代理 IP
配套关键头不能少
除 IP 外,其他头也影响路由、日志和安全判断:
-
proxy_set_header Host $http_host;—— 保留原始 Host,避免后端因 Host 错误返回 404 或生成错误链接 -
proxy_set_header X-Forwarded-Proto $scheme;—— 传递协议(HTTP/HTTPS),防止后端误判 HTTPS 状态 -
proxy_set_header X-Forwarded-Host $host;—— 保留原始域名,用于多租户或重定向逻辑
不复杂但容易忽略











