java应用经nginx反向代理后,需nginx配置set_real_ip_from、real_ip_header及real_ip_recursive,并在java中主动解析x-forwarded-for头(或启用remoteipvalve),才能获取真实客户端ip;同时须透传x-forwarded-proto、host等头以还原原始请求上下文。

Java 应用部署在 Nginx 反向代理后,若未正确配置,后端拿到的 REMOTE_ADDR 永远是 Nginx 的内网 IP(如 127.0.0.1 或 192.168.x.x),无法用于日志、限流、风控等场景。要真正透传客户端真实 IP,必须 Nginx 与 Java 应用协同配合——只配 header 不够,不设可信源会伪造,不改读取逻辑就白配。
确保 Nginx 正确设置并解析真实 IP 头
Nginx 不是“发出去就行”,它需要先识别谁是可信代理,再从请求头中提取真实 IP,最后才可用于透传:
- 用
set_real_ip_from明确声明可信上游(如 CDN 回源段、负载均衡器 IP、内网网关),例如:set_real_ip_from 10.0.0.0/8;set_real_ip_from 203.208.60.1; - 指定真实 IP 来源字段:
real_ip_header X-Forwarded-For;(若 CDN 或上层用该头)或real_ip_header X-Real-IP; - 开启递归解析:
real_ip_recursive on;,让 Nginx 自动剔除链路中已知代理 IP,取最左合法公网 IP 赋给$remote_addr - 在此基础上,
proxy_set_header X-Real-IP $remote_addr;和proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;才真正可靠
Java 应用必须主动从 Header 中读取,而非依赖 REMOTE_ADDR
Spring Boot、Tomcat、Jetty 等默认仍用底层 socket 的远程地址(即 Nginx IP)。需显式解析 HTTP 头:
- Spring Boot 推荐使用
HttpServletRequest.getRemoteAddr()前,先检查X-Forwarded-For:
若存在且非空,取逗号分隔后的第一个非私有 IP(如跳过127.0.0.1、10.0.0.0/8) - 可借助
org.springframework.web.util.WebUtils或自定义工具类封装 IP 提取逻辑,避免重复判断 - 若用 Tomcat,也可在
server.xml的RemoteIpValve中配置:<valve classname="org.apache.catalina.valves.RemoteIpValve" remoteipheader="X-Forwarded-For" protocolheader="X-Forwarded-Proto"></valve>,启用后getRemoteAddr()将自动返回解析后的结果
补充关键协议与主机头,避免 HTTPS 和 URL 构造错误
仅传 IP 不够,Java 应用常需还原原始请求上下文:
- 添加
proxy_set_header X-Forwarded-Proto $scheme;,让 Spring 的isSecure()或 Thymeleaf 的@{/xxx}生成正确 HTTPS 链接 - 保留原始 Host:
proxy_set_header Host $host;,防止 Java 中request.getServerName()返回 Nginx 配置的域名而非用户访问域名 - 如需精确端口(如非标准 HTTPS 端口),加
proxy_set_header X-Forwarded-Port $server_port;
验证与安全注意事项
配置生效后务必验证,同时防范伪造风险:
- 在 Java 日志中打印
request.getHeader("X-Forwarded-For")和request.getRemoteAddr()对比,确认值一致且为公网 IP - 禁止将
set_real_ip_from 0.0.0.0/0用于生产环境——这等于信任任意来源的X-Forwarded-For,极易被伪造 - 若 Java 应用暴露在公网且无前置 WAF/CDN,建议只信任 Nginx 直连 IP(如
set_real_ip_from 127.0.0.1;),并禁用外部直接访问后端端口
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











