mod_proxy_wstunnel仅透传http upgrade请求,真正双向通信依赖后端websocket协议实现;必须加载mod_proxy、mod_proxy_http和mod_proxy_wstunnel三模块,proxypass须用ws://前缀并前置,且需配置proxytimeout、后端ping/pong响应及upgrade/connection头透传。

Apache 本身不处理 WebSocket 协议,mod_proxy_wstunnel 的作用是透传 Upgrade 请求,把 WebSocket 连接“隧道化”交给后端服务完成全双工通信。真正实现客户端与服务器双向实时收发消息的能力,完全取决于后端是否正确实现了 WebSocket 协议(包括 ping/pong 响应、帧解析、连接维持等)。
必须启用并确认加载的模块
缺一不可,否则配置无效:
- mod_proxy(基础代理框架)
- mod_proxy_http(mod_proxy_wstunnel 内部依赖,用于建立底层 TCP 连接)
- mod_proxy_wstunnel(专用于识别和转发 WebSocket Upgrade 流量)
检查命令:httpd -M | grep -E "(proxy|wstunnel)";Debian/Ubuntu 可用 a2enmod proxy proxy_http proxy_wstunnel 启用。
安全更新和维护 CLI Proxy API(CPA)部署与配置。用于 CPA 镜像升级、配置变更、认证目录兼容修复、上线验证与回滚。适用于用户提到“CPA 更新/升级/配置改了/容器重建/回滚”等场景。
关键配置写法与顺序
ProxyPass 必须使用 ws:// 或 wss:// 协议前缀,且 WebSocket 路由要放在通用 HTTP 规则之前,否则请求被提前拦截:
- 正确示例(推荐):
ProxyPass "/ws/" "ws://127.0.0.1:8080/ws/" keepalive=OnProxyPassReverse "/ws/" "ws://127.0.0.1:8080/ws/" - 错误写法:
ProxyPass "/ws/" "http://127.0.0.1:8080/ws/"—— 会走普通 HTTP 代理,握手失败 - 若需动态识别,用 RewriteRule:
RewriteEngine OnRewriteCond %{HTTP:Upgrade} =websocket [NC]RewriteRule /ws/(.*) ws://127.0.0.1:8080/$1 [P,L]
避免连接中断的三项硬性调优
多数“能发不能收”或“几秒断连”问题都源于这三点未设:
-
显式延长超时:添加
ProxyTimeout 300(单位秒),默认 60 秒太短,WebSocket 长连接极易被 Apache 主动关闭 -
确保心跳可穿透:后端必须响应 ping 帧(如 Node.js ws 库默认支持;Spring Boot 需注册
PongMessageHandler;Go 的 gorilla/websocket 要调用conn.SetPingHandler()) -
头字段不被清洗:Upgrade 和 Connection 是 hop-by-hop 头,默认可能被过滤。可在配置中强制保留:
RequestHeader set Upgrade "websocket"RequestHeader set Connection "upgrade"
生产环境补充要点
高并发或负载均衡场景下还需注意:
- MPM 模式必须为 event(
a2dismod mpm_prefork && a2enmod mpm_event),prefork 在千级连接下极易内存溢出 - SSL 终止时,前端用
wss://,后端仍配ws://,Apache 自动解密再明文转发,降低后端 TLS 开销 - 若用 balancer,健康检查路径务必避开
/ws/,防止探测请求干扰长连接状态










