核心是启用mod_proxy及对应协议模块,在虚拟主机中按路径/协议分流请求至异构后端,并严格配置ProxyPass、头传递与安全控制。
在虚拟主机层级用 mod_proxy 实现统一反代网关,核心是让一个域名(如 app.example.com)对外暴露单一入口,同时将不同路径或子域名的请求,按协议类型分发到后端异构服务——比如 java 应用(http)、tomcat(ajp)、websocket 服务(ws)、fastcgi 程序(php),甚至 ftp 或 https 后端。关键不在“能不能”,而在于模块加载、协议匹配、头传递和路径隔离是否到位。
必须启用的模块组合
Apache 不会默认加载全部代理协议模块。仅靠 mod_proxy 本身无法处理非 HTTP 流量。需按需加载对应协议模块:
-
mod_proxy_http:代理标准 HTTP/HTTPS 请求(最常用) -
mod_proxy_ajp:对接 Tomcat 的 AJP 协议(端口默认 8009),比 HTTP 更高效 -
mod_proxy_wstunnel:支持 WebSocket(ws://和wss://),用于实时通信类服务 -
mod_proxy_fcgi:转发 FastCGI 请求(如 PHP-FPM),替代传统的mod_php -
mod_proxy_connect:仅在需要代理 SSL 隧道(如客户端直连 HTTPS 后端)时启用
验证方式:apache2ctl -M | grep proxy 或 httpd -M | grep proxy,确保列出所有已启用模块。缺失则在 mods-enabled/(Debian)或 httpd.conf 中补上 LoadModule 行,并重启前执行 apache2ctl configtest。
虚拟主机内按协议分流的典型配置
以 app.example.com 为例,在 <VirtualHost *:80> 或 <VirtualHost *:443> 块内分段定义:
- 主站(Java Spring Boot)走 HTTP:
ProxyPass / http://127.0.0.1:8080/<br>ProxyPassReverse / http://127.0.0.1:8080/<br>ProxyPreserveHost On
- AJP 接口(Tomcat 管理页)走子路径:
ProxyPass /tomcat/ ajp://127.0.0.1:8009/<br>ProxyPassReverse /tomcat/ ajp://127.0.0.1:8009/
- WebSocket 服务(如前端聊天)走独立路径:
ProxyPass /ws/ ws://127.0.0.1:9001/<br>ProxyPassReverse /ws/ ws://127.0.0.1:9001/
- PHP 后台接口走 FastCGI:
ProxyPass /api/php/ fcgi://127.0.0.1:9000/var/www/php-app/(注意路径映射)
⚠️ 注意:ProxyPass 路径末尾斜杠必须严格一致;ProxyPassReverse 必须配对,否则重定向头(如 302 Location)仍含内网地址;ProxyPreserveHost On 对 Java/Tomcat 类服务至关重要,否则生成的绝对 URL 会丢失原始域名。
安全更新和维护 CLI Proxy API(CPA)部署与配置。用于 CPA 镜像升级、配置变更、认证目录兼容修复、上线验证与回滚。适用于用户提到“CPA 更新/升级/配置改了/容器重建/回滚”等场景。
跨协议头传递与客户端真实信息还原
异构服务对请求头的解析能力差异大。要让后端(尤其是 Java/Spring Boot)拿到真实客户端 IP 和协议,不能只靠 Apache 默认行为:
- 强制注入标准转发头:
RequestHeader set X-Forwarded-Proto "http"<br>RequestHeader set X-Forwarded-Port "80"
(HTTPS 下改为https和443) - 确保
X-Forwarded-For包含原始 IP:
Apache 默认会追加,但若前端还有 CDN 或 Nginx,建议显式设置:RequestHeader set X-Forwarded-For "%{REMOTE_ADDR}e" env=REMOTE_ADDR - Java 应用必须启用信任代理头(如 Spring Boot 配置
server.forward-headers-strategy=framework,并设server.tomcat.remoteip.remote-ip-header=x-forwarded-for),否则request.getRemoteAddr()永远返回127.0.0.1
安全与权限控制要点
虚拟主机级反代不等于放行一切。常见疏漏点:
-
ProxyRequests Off必须显式写入虚拟主机块——这是关闭正向代理的关键,防止被滥用为开放代理 - 限制可代理的目标地址范围,避免 SSRF:
<Proxy "http://127.0.0.1:*"><br>Require ip 127.0.0.1<br></Proxy>
- 若使用 AJP,确保 Tomcat 的
server.xml中<Connector protocol="AJP/1.3">绑定在127.0.0.1,而非0.0.0.0 - WebSocket 场景下,需额外允许升级请求:
Header always set Access-Control-Allow-Origin "*"<br>Header always set Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization"<br>Header always set Access-Control-Allow-Methods "GET, POST, OPTIONS"<br>Header always set Access-Control-Allow-Credentials "true"
不复杂但容易忽略

















