apache反向代理需启用mod_proxy和mod_proxy_http模块,配对使用proxypass/proxypassreverse,设置proxypreservehost on、x-forwarded-proto及x-forwarded-for头,并确保java应用解析这些头以获取真实客户端ip和协议信息。

Apache 反向代理必须开启 mod_proxy 和 mod_proxy_http
没加载这两个模块,ProxyPass 会直接报 500 错误,日志里通常只写 Invalid command 'ProxyPass' 或更模糊的 Internal Server Error。Linux 发行版默认常不启用它们,Windows 下的 Apache 安装包也未必自带开启。
实操建议:
- 运行
httpd -M | grep proxy(或apache2ctl -M)确认proxy_module和proxy_http_module已 listed - 若未启用,在
httpd.conf或mods-enabled目录下补上:LoadModule proxy_module modules/mod_proxy.so和LoadModule proxy_http_module modules/mod_proxy_http.so - 重启 Apache 前务必先
apachectl configtest(或apache2ctl configtest),避免配置错误导致服务起不来
ProxyPass 和 ProxyPassReverse 必须配对使用
只写 ProxyPass,后端 Java 应用返回的重定向响应(比如 Spring Boot 的 302、或含 Location: http://192.168.1.100:8080/login 的 header)会把客户端直接暴露到内网地址;漏掉 ProxyPassReverse,用户点链接就跳错。
常见错误现象:页面能打开,但登录后跳转回 http://192.168.x.x:8080/xxx,或者静态资源 404。
实操建议:
- 假设 Java 服务跑在
http://127.0.0.1:8080,域名是app.example.com,则配置段应类似:
ProxyPreserveHost On ProxyPass / http://127.0.0.1:8080/ ProxyPassReverse / http://127.0.0.1:8080/
-
ProxyPreserveHost On很关键:它让 Apache 把原始Host请求头传给后端,否则 Java 应用可能生成错误的绝对 URL(比如用127.0.0.1:8080而非app.example.com) - 路径末尾斜杠必须一致——
ProxyPass /api/ http://.../api/,两边都带或都不带,否则路径拼接错乱
Java 应用需配合处理 X-Forwarded-* 头,否则 request.getRemoteAddr() 还是内网 IP
Apache 默认不会改写 X-Forwarded-For,但即使加了 RequestHeader set X-Forwarded-For "%{REMOTE_ADDR}e",Java 应用本身不解析这些头,getRemoteAddr() 返回的仍是 127.0.0.1,日志、限流、IP 白名单全失效。
使用场景:Spring Boot 项目需要真实客户端 IP 做风控或审计;传统 Servlet 应用要记录访问来源。
实操建议:
- Spring Boot 2.6+:在
application.yml加server.forward-headers-strategy: native(推荐),或显式配置server.tomcat.remote-ip-header: x-forwarded-for和server.tomcat.protocol-header: x-forwarded-proto - Tomcat 原生部署:修改
server.xml中Connector,加上remoteIpHeader="x-forwarded-for" protocolHeader="x-forwarded-proto" - 务必验证:在 Java 代码里打日志输出
request.getRemoteAddr()和request.getHeader("x-forwarded-for"),确认值已变成客户端公网 IP
HTTPS 到 HTTP 反向代理时,X-Forwarded-Proto 不设会导致 Spring Security 重定向死循环
前端是 HTTPS,后端是 HTTP,Spring Security 默认检测不到安全上下文,会反复 302 跳回 HTTPS 登录页,浏览器提示“重定向次数过多”。根本原因是没告诉 Java 应用“原始请求是 HTTPS”。
性能 / 兼容性影响:不设这个头,所有依赖协议判断的逻辑(如 OAuth 回调地址生成、HSTS 头注入)都会出错,且无法通过简单加 https:// 硬编码修复。
实操建议:
- 在 Apache 的
ProxyPass段里加一行:RequestHeader set X-Forwarded-Proto "https" - 如果 Apache 本身也跑在反代之后(比如前面还有 Nginx 或 CDN),应改为
RequestHeader set X-Forwarded-Proto expr=%{REQUEST_SCHEME},动态取当前协议 - 别信网上某些教程说“加个
ProxySet keepalive=On就行”,那个解决的是连接复用问题,跟协议识别无关
真实环境里最容易被忽略的,是 Java 应用内部生成的 URL(比如邮件里的重置链接、API 响应体中的 next_page 字段)——它们往往绕过 ProxyPassReverse,必须靠应用层读取 X-Forwarded-* 头来构造,否则用户点开就是 404 或跳内网。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










