使用Apache2作为Tomcat8代理时如何保留客户端IP?
我完全懂你碰到的这个困扰——当Apache作为反向代理把HTTPS请求转成HTTP发给Tomcat后,后端Spring Boot拿到的全是127.0.0.1,根本看不到真实的客户端IP。这是因为代理转发时没把原始IP传递给后端,下面是一套亲测有效的解决步骤:
第一步:修改Apache虚拟主机配置,传递真实IP与请求协议
在你sites-available目录下的目标配置文件里,除了已有的ProxyPass和ProxyPassReverse,补充以下配置,让Apache把真实客户端IP和原始请求协议(HTTPS)传递给Tomcat:
# 将真实客户端IP写入X-Forwarded-For请求头 RequestHeader set X-Forwarded-For "%{REMOTE_ADDR}s" # 告诉后端原始请求是HTTPS(因为Apache转成了HTTP发给Tomcat) RequestHeader set X-Forwarded-Proto "https" # 可选:传递原始请求的HTTPS端口 RequestHeader set X-Forwarded-Port "443"
另外,确保你已经启用了mod_headers模块,没启用的话执行这条命令:
a2enmod headers
修改完配置后,重启Apache让设置生效:
systemctl restart apache2
第二步:配置独立Tomcat(用嵌入式Tomcat直接看第三步)
如果你用的是独立部署的Tomcat,需要修改server.xml里的Connector节点,让Tomcat信任Apache的代理并解析X-Forwarded-For头:
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443"> <!-- 添加RemoteIpValve来解析代理传递的IP和协议头 --> <Valve className="org.apache.catalina.valves.RemoteIpValve" remoteIpHeader="X-Forwarded-For" protocolHeader="X-Forwarded-Proto" protocolHeaderHttpsValue="https"/> </Connector>
这个Valve会自动把X-Forwarded-For里的真实IP替换成Tomcat记录的客户端IP,同时识别原始的HTTPS协议。修改后重启Tomcat即可。
第三步:Spring Boot嵌入式Tomcat配置
如果你的Spring Boot用的是自带的嵌入式Tomcat,不用改独立Tomcat的配置,直接在application.properties或application.yml里添加以下配置:
application.properties写法:
# 告诉Spring Boot信任代理传递的请求头 server.forward-headers-strategy=framework # 注:Spring Boot 2.2版本前用下面两行替代: # server.tomcat.remote-ip-header=x-forwarded-for # server.tomcat.protocol-header=x-forwarded-proto
application.yml写法:
server: forward-headers-strategy: framework # 旧版本兼容写法: # tomcat: # remote-ip-header: x-forwarded-for # protocol-header: x-forwarded-proto
第四步:在Spring Boot中获取真实IP
配置完成后,你就可以通过HttpServletRequest直接拿到真实客户端IP了,代码示例:
import javax.servlet.http.HttpServletRequest; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class IpController { @GetMapping("/get-client-ip") public String getRealClientIp(HttpServletRequest request) { // 经过前面的配置,getRemoteAddr()已经返回真实客户端IP String realIp = request.getRemoteAddr(); return "客户端真实IP:" + realIp; } }
这样操作后,你的Spring Boot应用就能正确获取到客户端的真实IP,再也不会只拿到127.0.0.1啦。
内容的提问来源于stack exchange,提问作者Jamil Farooq

