不能在 http 块中用 proxy_set_header 透传真实客户端 IP,因为该指令仅在含 proxy_pass 的 location 或 server 块内生效;http 块无请求上下文,$remote_addr 等变量无法解析,header 不会被实际发送。

不能在 http 块 中用 proxy_set_header 透传真实客户端 IP。
为什么 http 块里配置无效
proxy_set_header 是代理指令,只在启用代理的上下文中生效(即存在 proxy_pass 的 location 或 server 块内)。http 块是全局配置层,不绑定具体请求,此时:
-
$remote_addr尚未确定——它依赖于当前 TCP 连接的来源,而 http 块加载时无连接上下文; -
$proxy_add_x_forwarded_for等变量也无法展开,会变成空值或字面字符串; - 即使写入,该 header 也不会被实际附加到任何代理请求中,形同虚设。
正确配置位置:必须在 location 或 server 块中
真实 IP 透传需结合具体代理动作,因此必须放在含 proxy_pass 的作用域内。典型写法如下:
proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header Host $host;proxy_set_header X-Forwarded-Proto $scheme;
这些语句要放在 proxy_pass 行之前,且每个需要代理的 location 都应单独配置。
仅靠 proxy_set_header 不够:还需可信链路识别
若 Nginx 前面还有 CDN、WAF 或负载均衡器(如阿里云 SLB),$remote_addr 实际是它们的出口 IP,不是用户真实 IP。此时必须配合:
-
set_real_ip_from:声明可信代理的 IP 段(如set_real_ip_from 100.64.0.0/10;); -
real_ip_header X-Forwarded-For;:指定从哪个 header 解析真实 IP; -
real_ip_recursive on;:逐级剔除可信代理 IP,保留最左原始 IP。
这些指令可放在 http、server 或 location 块中,但必须与 proxy_set_header 协同使用才有效。
后端必须主动读取,不能依赖 REMOTE_ADDR
Nginx 只负责把 IP 写进 header,后端框架默认仍返回连接方地址(如 getRemoteAddr() 或 req.connection.remoteAddress)。你必须显式提取:
- Node.js:读
req.headers['x-real-ip']或解析x-forwarded-for最左非私有 IP; - Java Servlet:用
request.getHeader("X-Real-IP"); - Python Flask:用
request.environ.get('HTTP_X_REAL_IP'); - PHP:
$_SERVER['HTTP_X_REAL_IP']。


















