nginx 多级代理链路追踪需构建可信 ip 传递链:首跳用 $remote_addr 初始化 x-forwarded-for,中间层用 $proxy_add_x_forwarded_for 追加,末层启用 realip 模块校验可信源并提取真实 ip,后端应读 x-real-ip 或框架封装方法获取真实客户端地址。

要让 Nginx 在多级代理中准确支持链路追踪,关键不是“加一个头”,而是建立一条可信、可延续、防伪造的 IP 与路径传递链。每一层都必须明确自己该传什么、该信谁,否则 X-Forwarded-For 会断裂或污染,真实客户端 IP 就无法抵达后端。
每层必须用 $proxy_add_x_forwarded_for 追加而非覆盖
这是构建完整链路的基础操作:
- 首跳代理(如 CDN 或最外层 Nginx)若直连公网客户端,应初始化为
proxy_set_header X-Forwarded-For $remote_addr; - 后续所有中间层(如 LB → 网关 → 应用 Nginx)统一使用:
proxy_set_header X-Forwarded-For "$proxy_add_x_forwarded_for";
它等价于"$http_x_forwarded_for, $remote_addr",自动处理“有则追加、无则填” - 严禁写成
proxy_set_header X-Forwarded-For $remote_addr——这会丢弃上游所有记录,只剩最后一跳 IP
最终接入层必须启用 realip 模块校验可信来源
仅靠 X-Forwarded-For 不安全,攻击者可伪造。最后一层 Nginx 需完成可信剥离:
- 确认已编译启用
--with-http_realip_module - 在
http或server块中声明可信上游段:set_real_ip_from 10.0.0.0/8;<br>set_real_ip_from 172.16.0.0/12;<br>set_real_ip_from 192.168.0.0/16;<br>set_real_ip_from 173.245.48.0/20; # Cloudflare
- 指定解析头:
real_ip_header X-Forwarded-For; - 开启递归解析:
real_ip_recursive on;——Nginx 从右往左跳过所有可信 IP,取第一个非可信地址作为真实客户端 IP,并更新$remote_addr
配套透传其他关键请求头
光有 X-Forwarded-For 不够,还需同步修正并传递上下文信息:
-
proxy_set_header X-Real-IP $remote_addr;:注入经 realip 修正后的客户端 IP(后端可直接读) -
proxy_set_header X-Forwarded-Proto $scheme;:确保后端知道原始是 HTTP 还是 HTTPS -
proxy_set_header Host $host;:避免后端重定向时拼错域名 - 禁用
underscores_in_headers on;,防止自定义头(如X-Trace-ID)被静默丢弃
后端服务要读修正后的值,而不是手动解析 XFF
应用代码不应再对 X-Forwarded-For 字符串做切分或取首 IP:
- 优先读取
X-Real-IP头(由 Nginx 注入,已通过 realip 校验) - 或直接调用框架封装的获取方式,例如:
Java 中HttpServletRequest.getRemoteAddr()(realip 生效后即为真实 IP)
PHP 中$_SERVER['REMOTE_ADDR']
Node.js 中req.ip(配合trust proxy设置) - 若需链路全貌(如审计、排障),可记录完整
X-Forwarded-For值到日志,但业务逻辑绝不依赖它做权限或限流判断











