hyperf单机部署websocket需确保nginx透传upgrade/connection头、proxy_read_timeout≥heartbeat_idle_time+20、swoole heartbeat_check_interval与heartbeat_idle_time差值≥20并重启生效。

Hyperf单机部署WebSocket服务时,Nginx穿透配置的关键不是“加个反向代理就行”,而是确保协议升级不被截断、心跳不断连、连接不被超时误杀。核心就三点:透传Upgrade头、调大超时值、配对Swoole心跳参数。
Nginx必须透传WebSocket握手头
如果Nginx没正确转发Upgrade和Connection头,客户端连握手都失败,直接返回400或静默丢包。这不是后端问题,是代理层拦在了第一步。
- 确认配置里有这三行(缺一不可):
proxy_http_version 1.1;<br>proxy_set_header Upgrade $http_upgrade;<br>proxy_set_header Connection "upgrade";
- 宝塔面板用户可在「网站 → 反向代理 → 配置修改」里手动追加,不要依赖默认模板
- 用curl测试是否生效:
curl -i -H "Upgrade: websocket" -H "Connection: upgrade" http://your-domain.com/ws,响应中应含HTTP/1.1 101 Switching Protocols
超时时间要大于心跳缓冲窗口
Nginx默认proxy_read_timeout=60s,而Hyperf/Swoole心跳若设为每45秒一次,网络稍有延迟就会在第61秒被Nginx主动断开——客户端看到的就是code=1001或直接断连。
- 推荐生产配置(写在location块内):
proxy_read_timeout 86400;<br>proxy_send_timeout 86400;
- 若资源受限,至少设为
90,且必须 >heartbeat_check_interval + 20(比如检查间隔25s,空闲上限60s,则Nginx超时至少85s) - 注意:这些值只对当前location生效,不能写在http块顶层后就以为全局覆盖
Swoole心跳参数需静态配对并重启
Hyperf本身不处理ping/pong帧逻辑,它依赖Swoole底层用heartbeat_check_interval和heartbeat_idle_time判断连接存活。填错组合会导致弱网下频繁踢人。
- 在
config/autoload/server.php的WebSocket server配置中,加入settings项:'settings' => [<br> 'heartbeat_check_interval' => 25,<br> 'heartbeat_idle_time' => 60,<br>],
- 两个值差必须≥20秒(如25和60),留出网络抖动余量
- 改完必须重启服务:
php bin/hyperf.php start,热重载不生效 - 客户端需能响应标准PING帧(原生WebSocket会自动回PONG;若发JSON ping,服务端得自己解析并回PONG)
验证与常见漏点
配置完别急着上线,先做三件事:
- 用浏览器控制台
new WebSocket("wss://your-domain.com/ws")直连,看console是否报错,Network里看Status是否101 - 抓包确认:Wireshark或Chrome DevTools Network → WS → Frames,应能看到连续的ping/pong帧交互
- 检查Swoole日志:
tail -f runtime/logs/swoole.log,留意是否有heartbeat timeout或connection closed记录 - 常见漏点:HTTPS证书未覆盖WS域名(wss需对应域名证书)、防火墙放行了80/443但没放通后端WebSocket端口(如9502)、宝塔开了反向代理却没关“强制HTTPS”导致ws被301跳转











