Apache不处理WebSocket心跳,仅透传并防断连;需启用mod_proxy_wstunnel、用ws/wss协议代理、透传Upgrade/Connection头、调大Timeout和ProxyTimeout、禁用缓存与重写、负载均衡时启用Sticky Session。
apache 本身不生成或处理 websocket 心跳帧(如 ping/pong),它的作用是透传心跳、维持隧道、防止空闲断连。保活的关键不是“发心跳”,而是让心跳能真实走通,并确保连接在空闲时不被 apache 或中间网络设备切断。
✅ 必须启用 mod_proxy_wstunnel 模块
mod_proxy_http 无法识别 WebSocket 升级握手,会把 Upgrade: websocket 请求当作普通 HTTP 处理,导致连接被静默关闭(常见错误:1006 ABNORMAL)。
- 启用方式(Ubuntu/Debian):
sudo a2enmod proxy proxy_http proxy_wstunnel headers sudo systemctl restart apache2
- 验证是否加载成功:
httpd -M | grep -E "(proxy|headers)" # 应看到 proxy_module、proxy_http_module、proxy_wstunnel_module、headers_module(均为 shared)
✅ ProxyPass 必须用 ws:// 或 wss:// 协议前缀
路径匹配必须严格,末尾 / 不可省略,否则协议升级失败:
ProxyPass "/ws" "ws://localhost:8080/" ProxyPassReverse "/ws" "ws://localhost:8080/"
- ❌ 错误写法:
http://localhost:8080/(走 HTTP 代理,丢弃 Upgrade) - ❌ 错误写法:
/ws/→ws://localhost:8080(路径不匹配,握手头可能丢失)
✅ 强制透传 Upgrade 和 Connection 头部
Apache 默认不转发 Upgrade 和 Connection: upgrade,需显式设置:
<location>
ProxyPreserveHost On
RequestHeader set Connection "upgrade"
RequestHeader set Upgrade "websocket"
</location>
-
mod_headers必须启用; -
Upgrade值要写死为"websocket"(WSS 场景也如此,不是"wss"); -
Connection必须设为"upgrade",不能是"keep-alive"或留空。
✅ 调整超时参数,匹配心跳节奏
心跳间隔由前后端约定(例如每 30 秒发一次 Ping),Apache 的超时必须大于最大可能空闲时间(建议 ≥ 心跳间隔 × 2):
Timeout 3600 ProxyTimeout 3600
-
Timeout控制整个请求生命周期(含握手); -
ProxyTimeout控制代理隧道建立后的空闲等待时间; - 两者都设为 3600(1 小时)可覆盖绝大多数心跳场景(如 30–45 秒心跳);
- 不建议设为 86400(24 小时):长期空闲连接会累积文件描述符与内存压力。
✅ 禁用干扰行为
避免 Apache 对 WebSocket 连接做无意义干预:
- 关闭缓存相关指令(如
CacheIgnoreHeaders、ExpiresActive); - 不使用
AddOutputFilterByType或SetOutputFilter处理/ws路径; - 不在
中启用RewriteEngine(除非明确需要重写路径,且不破坏 Upgrade 流程)。
✅ 负载均衡场景:必须开启 Sticky Session
若后端是多实例集群(如多个 Python websockets 进程),WebSocket 连接必须始终路由到同一节点:
<proxy>
BalancerMember ws://192.168.1.10:8080 route=node1
BalancerMember ws://192.168.1.11:8080 route=node2
ProxySet stickysession=ROUTEID
</proxy>
ProxyPass "/ws" "balancer://wscluster/"
# 并确保后端在响应中设置 Set-Cookie: ROUTEID=...; Path=/; HttpOnly
否则客户端重连可能落到无状态的新节点,导致认证丢失或消息中断。
不复杂但容易忽略











