要让后端拿到客户端真实IP和原始端口,必须Nginx配置透传头(X-Real-IP、X-Forwarded-For、X-Forwarded-Port等)、启用realip模块限定可信代理并递归解析、后端主动读取校验后的HTTP_X_REAL_IP或X-Forwarded-For首IP。

要让后端应用拿到客户端真实 IP 和原始端口,不能只靠加几个 header,得从 Nginx 配置、可信链校验、到后端读取逻辑三者配合。漏掉任何一环,后端拿到的可能还是 127.0.0.1 或代理内网地址。
透传真实 IP 的核心配置
Nginx 在 proxy_pass 前必须显式设置以下头字段:
-
X-Real-IP:设为
$remote_addr,这是当前连接的直接上游 IP。单层代理时即用户真实 IP;多层时需先经 realip 模块解析后再设 -
X-Forwarded-For:用
$proxy_add_x_forwarded_for,它会自动在已有值末尾追加当前$remote_addr,保留完整转发路径(如:203.100.5.1, 192.168.10.2, 10.0.1.5) -
X-Forwarded-Proto:设为
$scheme,透传 http/https,避免后端误判安全上下文 -
X-Forwarded-Host 和 X-Forwarded-Port:分别设为
$host和$server_port,便于后端生成正确跳转链接或构建绝对 URL
限定可信代理,防止 IP 被伪造
仅设 header 是不安全的——客户端可手动发 X-Forwarded-For: 1.2.3.4 伪造。Nginx 必须知道哪些来源可信,才信任其传来的头:
- 确认已启用
http_realip_module(可通过nginx -V | grep http_realip_module验证) - 在
http或server块中列出所有可信代理出口 IP 或网段:set_real_ip_from 192.168.0.0/16;set_real_ip_from 10.0.0.0/8;set_real_ip_from 203.205.0.0/16;(例如 CDN 出口段) - 指定从哪个头提取真实 IP:
real_ip_header X-Forwarded-For;或更可控的real_ip_header X-Real-IP; - 开启递归解析:
real_ip_recursive on;,Nginx 会从右往左剔除已知代理 IP,最终把第一个非代理 IP 赋给$remote_addr
后端应用必须主动读取对应 Header
Nginx 设置只是“发出去”,后端默认仍读 REMOTE_ADDR(即 Nginx 连接 IP)。必须显式从 header 中提取:
-
Java(Spring Boot):配置
server.forward-headers-strategy=framework,并确保TomcatServletWebServerFactory启用setRemoteIpHeader("X-Real-IP") -
Python Flask:使用
ProxyFix中间件,明确指定num_proxies或trusted_hosts -
Node.js Express:调用
app.set('trust proxy', true),并确认 Nginx 已透传X-Forwarded-For和X-Forwarded-Proto -
通用安全顺序:优先读
HTTP_X_REAL_IP(经 realip 模块校验),其次取HTTP_X_FORWARDED_FOR中第一个非私有 IP(如剔除 127.0.0.1、192.168.x.x、10.x.x.x),最后才 fallback 到REMOTE_ADDR
端口透传的注意事项
客户端原始端口本身无法直接透传(TCP 层无标准字段承载),但可通过 X-Forwarded-Port 提供参考值:
-
proxy_set_header X-Forwarded-Port $server_port;记录的是 Nginx 接收请求时所用的端口(如 443 或 80),不是客户端发起连接的源端口 - 若需真正获取客户端源端口,只能由客户端在请求体或自定义 header 中携带(如
X-Client-Port),且需业务层约定与校验 - 多数场景下,
X-Forwarded-Port已足够用于判断协议类型和构造重定向 URL


















