必须启用 ProxyPreserveHost on,否则 Apache 会将 Host 头替换为后端地址(如 localhost:8080),导致 Spring Boot、Django、Express 等后端无法识别真实域名 api.example.com,引发 SAML 验证失败、路由错乱或 400/404 错误;该指令须与 ProxyPass 同处于 <VirtualHost> 或 <Location> 等代理作用域内,不可全局配置,且不继承。

要让后端服务(如 Spring Boot、Django、Express)正确识别用户访问的真实域名(比如 api.example.com),必须启用 ProxyPreserveHost on。默认情况下,Apache 会把请求中的 Host 头替换成后端地址(如 localhost:8080),导致后端生成错误的绝对 URL、SAML 验证失败、多租户路由错乱,甚至返回 400/404 错误。
必须开启并放在正确位置
ProxyPreserveHost on 不是全局指令,也不能写在主配置顶层。它只在启用代理的上下文中生效,且必须和 ProxyPass 处于同一作用域:
- 放在
<VirtualHost>块内(最常见) - 或嵌套在
<Location>或<Proxy>块中(用于路径级或负载均衡代理) - 若用多个
ProxyPass(如分别代理/api和/auth),每个块里都要单独加一行ProxyPreserveHost on,它不继承
典型最小可用配置示例
以下是在虚拟主机中转发全部请求到本地 Java 应用的标准写法:
<VirtualHost *:80>
ServerName api.example.com
ProxyPreserveHost on
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/
</VirtualHost>
注意:ProxyPass 和 ProxyPassReverse 的路径末尾斜杠必须一致;ProxyPassReverse 不可省略,否则 302 跳转会暴露内网地址。
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
配合后端正确解析域名
仅配 Apache 还不够,后端应用需依赖原始 Host 头做逻辑判断。常见处理方式:
- Spring Boot:默认已通过
ForwardedHeaderFilter解析,但需确保server.forward-headers-strategy=framework - Node.js(Express):启用
app.set('trust proxy', true),再用req.hostname获取真实域名 - Django:设置
USE_X_FORWARDED_HOST = True,并确认SECURE_PROXY_SSL_HEADER配合X-Forwarded-Proto - 避免同时依赖
X-Forwarded-Host:它只是附加头,而ProxyPreserveHost on直接透传标准Host,更可靠、更通用
验证是否生效
检查后端日志或临时加调试输出,确认收到的 Host 请求头是 api.example.com,而非 127.0.0.1 或 localhost:8080。也可用 curl 模拟请求:
curl -H "Host: api.example.com" http://your-apache-server/health
然后查看后端 access log 或打印出的 request headers。如果看到的是原始域名,说明配置已起效。

















