必须设为on才能透传原始host头,否则apache会将其替换为后端地址(如localhost:3000),导致后端无法识别用户真实访问域名(如api.example.com),引发400/404/502错误。
要让后端服务正确识别用户访问的真实域名(比如 api.example.com),而不是看到 localhost:3000 或 127.0.0.1,必须在 apache 虚拟主机中正确启用 proxypreservehost。它不是可选项,而是多域名反向代理场景下的关键开关。
为什么必须在 VirtualHost 里配 ProxyPreserveHost on
Apache 的 mod_proxy 默认会把原始请求里的 Host 头替换成后端地址(如 localhost:3000)。后端应用(如 Express、Django、Spring Boot)若依赖 Host 判断租户、路由或生成绝对 URL,就会出错——常见表现是返回 400、404 或 502,日志里能看到 Host 是内部地址而非用户真实访问域名。
- 该指令只在启用代理时生效,且仅对当前作用域有效(不继承)
- 必须和 ProxyPass 写在同一级配置块内(
或 ),写在全局 Server 配置或 .htaccess 中无效 - 如果一个虚拟主机里有多个 ProxyPass,每个都要单独加一行 ProxyPreserveHost on
最小可用的虚拟主机配置示例
以下是在 /etc/apache2/sites-available/your-site.conf 中的标准写法:
安全更新和维护 CLI Proxy API(CPA)部署与配置。用于 CPA 镜像升级、配置变更、认证目录兼容修复、上线验证与回滚。适用于用户提到“CPA 更新/升级/配置改了/容器重建/回滚”等场景。
<virtualhost>
ServerName api.example.com
ProxyPreserveHost on
ProxyPass / http://127.0.0.1:3000/
ProxyPassReverse / http://127.0.0.1:3000/
</virtualhost>
- ServerName 必须与用户实际访问的域名一致(区分大小写)
- ProxyPassReverse 不可省略:它重写响应头中的 Location、Content-Location 等 URL,防止 302 跳转暴露后端地址
- HTTPS 场景下,ProxyPass 目标可写成
https://localhost:8443/,但需确保后端支持并已配好证书
常见错误排查点
- 模块未启用:运行
a2enmod proxy proxy_http(Debian/Ubuntu)或确认mod_proxy.so和mod_proxy_http.so已加载(RHEL/CentOS) - 配置位置错:检查 ProxyPreserveHost on 是否真的在
标签内,而不是被误放在 或全局段 - 配置未生效:修改后必须执行
apachectl configtest && systemctl reload apache2(或httpd -t && systemctl reload httpd) - 日志验证:开启 Apache 的 access_log 和 error_log,再用 curl -H "Host: api.example.com" http://127.0.0.1 测试,观察后端是否收到正确的 Host 头
要不要同时配 X-Forwarded-Host
ProxyPreserveHost 和 X-Forwarded-Host 解决不同问题:
- 前者直接透传原始 Host 请求头给后端,是多数框架默认信任的来源
- 后者是额外添加的自定义头,需后端主动读取(如 Express 中要手动取
req.get('X-Forwarded-Host')) - 两者可以共存,但若后端只认 Host 头(推荐做法),就无需额外加 X-Forwarded-Host










