正确配置需先设可信代理段(set_real_ip_from)、指定真实IP头(real_ip_header)并开启递归解析(real_ip_recursive on),再用proxy_set_header透传;否则$remote_addr仍是代理IP而非用户真实IP。

直接用 proxy_set_header X-Real-IP $remote_addr; 是常见做法,但能否真正传到后端、是否真实,取决于 Nginx 所处位置和配置完整性。只写这一行,大概率传的是代理 IP,不是用户真实 IP。
得先让 $remote_addr 变成真实 IP,再透传
Nginx 默认的 $remote_addr 是跟它建立 TCP 连接的上一跳地址(比如 CDN 节点、SLB 或 WAF 的出口 IP)。要让它变成用户真实 IP,必须告诉 Nginx:“哪些上游是可信的,它们传来的 X-Forwarded-For 或 X-Real-IP 我才认”。
-
在
http、server或location块中添加可信代理段
比如阿里云 SLB 回源段、Cloudflare 官方 IP 段、或你自己的内网网关:set_real_ip_from 10.0.0.0/8; set_real_ip_from 192.168.0.0/16; set_real_ip_from 203.205.128.0/17; # 示例:阿里云实际段,请按文档替换
-
指定从哪个头提取真实 IP
多数 CDN 和 WAF 用X-Forwarded-For,推荐:real_ip_header X-Forwarded-For; real_ip_recursive on;
开启
recursive on后,Nginx 会从X-Forwarded-For值(如203.0.113.1, 198.51.100.2, 192.168.1.100)中,从右往左剔除所有已声明的可信代理 IP,最终把最左边那个非私有、非代理的 IP 设为新的$remote_addr。
再用 proxy_set_header 把它安全透传出去
确保这些指令写在 proxy_pass 行之前,且基于已修正的 $remote_addr:
-
单值清晰,后端可直取:
proxy_set_header X-Real-IP $remote_addr;
-
兼容多层链路,保留完整路径(推荐同时配):
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
注意:用
$proxy_add_x_forwarded_for而不是$remote_addr,它会自动继承上游已有值并追加当前层真实 IP,避免覆盖原始用户 IP。
后端必须主动读取,不能依赖 REMOTE_ADDR
Nginx 不会自动改写后端的 REMOTE_ADDR 或 req.connection.remoteAddress。框架默认返回的仍是 Nginx 的连接 IP(如 127.0.0.1)。你需要代码里显式提取:
- PHP:
$_SERVER['HTTP_X_REAL_IP'] - Node.js(Express):
req.headers['x-real-ip']或req.headers['x-forwarded-for']?.split(',')[0].trim() - Python(Flask):
request.headers.get('X-Real-IP') - Java(Servlet):
request.getHeader("X-Real-IP")
如果还希望 Nginx 自己的 access_log 记录真实 IP,复用上面 set_real_ip_from + real_ip_header 配置即可,日志变量 $remote_addr 就会自动变成用户真实 IP。
不复杂但容易忽略


















