Nginx 反向代理后客户端 IP 变成 127.0.0.1 怎么获取真实 IP

文章导读
在 Nginx 反向代理场景中,后端服务获取到 127.0.0.1 是因为 TCP 连接直接来自 Nginx 本地。解决方法是在 Nginx 配置中通过 proxy_set_header 传递 X-Real-IP 和 X-Forwarded-For 头部,并在后端代码中优先读取这两个头部字段。
📋 目录
  1. A 命令速用版
  2. B 为什么会这样
  3. C 分步处理
  4. D 怎么验证是否生效
  5. E 常见坑
  6. F 常见问题
  7. G 参考来源
A A

在 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)需额外配置信任代理中间件才能自动识别这些头部。

Nginx 反向代理后客户端 IP 变成 127.0.0.1 怎么获取真实 IP

常见问题

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 日)