在 Nginx 反向代理场景中,后端服务获取到 127.0.0.1 是因为 TCP 连接直接来自 Nginx 本地。解决方法是在 Nginx 配置中通过 proxy_set_header 传递 X-Real-IP 和 X-Forwarded-For 头部,并在后端代码中优先读取这两个头部字段。
先说结论:必须同时在 Nginx 层写入头部信息并在后端应用层读取头部信息,仅修改一端无法生效。
- 适合:使用 Nginx 作为反向代理且后端为 Java、Python、PHP 或 Go 的 Web 服务场景。
- 先准备:确认 Nginx 配置文件路径(通常为/etc/nginx/nginx.conf)及后端服务支持自定义 Header 读取。
- 验收:后端日志或代码输出中显示的客户端 IP 应为公网 IP 而非 127.0.0.1 或内网 IP。
命令速用版
在 Nginx 的 server 或 location 配置块中添加以下指令,保存后执行 nginx -s reload 重载配置。
location / {
proxy_pass http://backend_server;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}为什么会这样
Nginx 作为反向代理时,后端服务器建立的 TCP 连接对象是 Nginx 服务器本身。默认情况下,后端服务通过 request.getRemoteAddr() 或类似方法获取的是直接连接者的 IP 地址,即 Nginx 的内网 IP 或 127.0.0.1。HTTP 协议本身不携带原始客户端 IP,必须通过自定义 Header 显式传递。
分步处理
第一步:修改 Nginx 配置。打开 Nginx 配置文件,在对应的 location 块中加入 proxy_set_header 指令,将$remote_addr 变量写入 X-Real-IP 头部,将$proxy_add_x_forwarded_for 变量写入 X-Forwarded-For 头部。
第二步:配置后端代码读取。Java 应用需修改获取 IP 的工具类,优先判断 X-Forwarded-For 头部是否为空或 unknown,其次判断 X-Real-IP,最后才使用 request.getRemoteAddr()。Python Flask 应用可直接读取 request.headers.get('X-Forwarded-For')。
第三步:安全加固。如果 Nginx 前方还有其他负载均衡器,需在 Nginx 中配置 set_real_ip_from 指令指定可信代理 IP 段,防止用户伪造 X-Forwarded-For 头部。
怎么验证是否生效
查看后端应用日志,确认记录的 IP 字段已变为客户端公网 IP。使用 curl 命令模拟请求并指定 Header,例如 curl -H "X-Forwarded-For: 1.2.3.4" http://your-domain.com,观察后端接收到的 IP 是否被正确识别。检查 Nginx 访问日志,确认$proxy_add_x_forwarded_for 变量已记录到日志格式中。
常见坑
X-Forwarded-For 头部可被客户端伪造,不可直接用于安全验证或权限控制。多层代理场景下,X-Forwarded-For 可能包含多个 IP,需取第一个非可信代理的 IP。IPv6 环境下,本地回环地址为::1,代码逻辑需同时兼容 127.0.0.1 和::1 的判断。部分 Web 框架(如 Django、Spring Boot)需额外配置信任代理中间件才能自动识别这些头部。
常见问题
Java 如何获取 Nginx 传递的真实 IP?
优先读取 request.getHeader("X-Forwarded-For"),若为空则读取 request.getHeader("X-Real-IP"),最后降级为 request.getRemoteAddr()。
Python Flask 如何获取真实 IP?
使用 request.headers.get('X-Forwarded-For') 获取,若存在多个 IP 通常取第一个,或者直接使用 request.remote_addr 配合 TrustedProxy 中间件。
Nginx 日志如何记录真实 IP?
修改 log_format 配置,将$remote_addr 替换为$http_x_forwarded_for 或$proxy_add_x_forwarded_for 变量。
参考来源
使用 Nginx 反向代理后如何获取真实请求者的 IP 地址 (2024 年 1 月 17 日)
HoRain 云`--nginx` 反向代理如何获取真实 IP? (2025 年 2 月 13 日)
nginx 反向代理如何获取真实 IP? - Ruthless - 博客园 (2017 年 8 月 21 日)
【Nginx】如何获取客户端真实 IP、域名、协议、端口?看这一篇就够了!(2024 年 4 月 19 日)