Apache不实现WebSocket协议,mod_proxy_wstunnel仅透传Upgrade握手请求并隧道化交给后端;稳定双向通信取决于后端正确响应ping/pong及Apache启用mod_proxy、mod_proxy_http、mod_proxy_wstunnel三模块,ProxyPass须用ws://前缀且前置,配置ProxyTimeout≥300、保留Upgrade/Connection头,并高并发时切换event MPM。

Apache 本身不实现 WebSocket 协议,mod_proxy_wstunnel 的作用是安全透传 HTTP Upgrade 握手请求,把 WebSocket 连接“隧道化”交给后端服务处理。能否稳定双向通信,关键在后端是否正确响应 ping/pong、维持帧连接,以及 Apache 是否配置到位。
必须启用的三个基础模块
缺一不可,否则 ProxyPass ws:// 不生效:
- mod_proxy:代理框架核心
- mod_proxy_http:wstunnel 内部依赖,用于建立底层 TCP 连接
- mod_proxy_wstunnel:识别 Upgrade: websocket 并触发隧道转发
检查命令:httpd -M | grep -E "(proxy|wstunnel)",应全部显示 shared。
Ubuntu/Debian 环境启用方式:sudo a2enmod proxy proxy_http proxy_wstunnel && sudo systemctl restart apache2
ProxyPass 必须用 ws:// 前缀且前置
这是触发 wstunnel 的唯一开关。规则顺序很重要——WebSocket 路由必须写在普通 HTTP 规则之前,否则请求被 / 拦截,根本到不了后端:
- ✅ 正确:
ProxyPass "/ws/" "ws://127.0.0.1:8080/ws/" keepalive=On - ❌ 错误:
ProxyPass "/ws/" "http://127.0.0.1:8080/ws/"(走普通 HTTP 代理,握手失败) - 路径末尾斜杠需一致,避免 Sec-WebSocket-Location 头错乱
防止静默断连的三项硬性设置
多数“能发不能收”或“几秒掉线”问题都源于这三点未设:
-
显式延长超时:添加
ProxyTimeout 300(单位秒),默认 60 秒太短,长连接极易被主动关闭 -
确保心跳穿透:后端必须响应 WebSocket 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:prefork 或 worker 无法高效支撑空闲长连接,event 才支持异步 I/O;切换命令:
a2dismod mpm_prefork && a2enmod mpm_event -
协同调优连接参数:
Timeout 600、KeepAlive On、KeepAliveTimeout 300、MaxKeepAliveRequests 0 - 负载均衡时,健康检查路径避开
/ws/,避免干扰长连接


















