核心是用$proxy_add_x_forwarded_for透传x-forwarded-for(自动追加不覆盖),配set_real_ip_from和real_ip_header识别真实ip并更新$remote_addr,再设x-real-ip $remote_addr;后端须信任nginx来源并主动读取,不可依赖remote_addr。

在 Nginx 中使用 proxy_set_header 传递客户端真实 IP,核心是正确设置 X-Forwarded-For 和 X-Real-IP 请求头,并确保上游服务(如后端应用)能安全、可靠地读取它们。
为什么要设这两个头?
X-Forwarded-For 是事实标准,用于记录请求经过的代理链中各层的客户端 IP(逗号分隔),例如:X-Forwarded-For: 203.0.113.42, 192.168.10.5
最左边是原始客户端 IP,后续是各级代理 IP。X-Real-IP 则通常只存最终可信来源的 IP(常由 Nginx 自己决定),更简洁,适合后端直接信任使用。
基础配置写法(推荐)
在 location 或 server 块中添加:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
说明:
• $proxy_add_x_forwarded_for 是 Nginx 内置变量:如果上游已有 X-Forwarded-For,就追加 $remote_addr;否则直接设为 $remote_addr。它比硬写 $remote_addr 更健壮。
• $remote_addr 是与 Nginx 建立 TCP 连接的直接客户端地址 —— 若 Nginx 前面没有其他代理(如 CDN、负载均衡器),这就是真实用户 IP;若前面有可信代理,则需进一步处理。
前面有可信代理(如 SLB、CDN)时怎么处理?
当 Nginx 不是第一层入口(例如部署在阿里云 SLB 后、Cloudflare 后),$remote_addr 只是上一跳代理的 IP,不能代表用户。此时应信任代理通过特定头传来的 IP,常见做法:
- 确认代理是否透传了真实 IP(如阿里云 SLB 默认用
X-Forwarded-For,Cloudflare 用Cf-Connecting-IP) - 用
set_real_ip_from+real_ip_header让 Nginx 识别并覆盖$remote_addr - 示例(假设 SLB 网段是
100.64.0.0/10,且它把真实 IP 放在X-Forwarded-For最左):
set_real_ip_from 100.64.0.0/10;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
配置后,$remote_addr 就变成真实客户端 IP,上面的 proxy_set_header X-Real-IP $remote_addr 才真正有效。
后端应用怎么安全使用这些头?
仅靠 Nginx 设置头还不够,后端必须只信任来自 Nginx 的请求,并忽略不可信来源的 X-Forwarded-For。常见风险:
- 攻击者伪造
X-Forwarded-For: 1.2.3.4直接发到后端 → 日志/限流误判 - 未限制可信代理网段,导致任意请求都能“冒充”内网 IP
建议:
• 后端只从直连 Nginx 的连接中读取 X-Real-IP 或 X-Forwarded-For
• 若后端是 Node.js/Python/Java,用官方反向代理中间件(如 Express 的 trust proxy、Django 的 SECURE_PROXY_SSL_HEADER)并设好可信代理 CIDR
• 避免在代码里无条件取 request.headers['x-forwarded-for'].split(',')[0]











