wss连通核心是nginx正确透传upgrade和connection头、终止tls并保持长连接:必须设proxy_http_version 1.1,配对使用proxy_set_header upgrade $http_upgrade与proxy_set_header connection "upgrade",并调大proxy_read_timeout和proxy_send_timeout至3600秒以上。

wss 要能连通,核心不是“加个SSL”就行,而是 Nginx 必须正确透传 WebSocket 的协议升级请求,并终止 TLS 同时保持长连接不中断。配置错一个头、漏一个超时,前端就会卡在 CONNECTING 状态或秒断。
为什么 wss:// 连不上?常见错误现象
浏览器控制台报错 WebSocket connection to 'wss://...' failed,或者反复触发 onclose 且 event.code === 1006;后端日志里根本收不到 Upgrade 请求;Nginx access_log 显示返回了 400 或 502。这些基本都指向同一个问题:Nginx 没把客户端的 Upgrade: websocket 和 Connection: Upgrade 头转发给后端,或者转发了但没告诉 Nginx “这是 WebSocket 流量,别按普通 HTTP 处理”。
proxy_set_header Upgrade $http_upgrade 必须配对使用
单独写这一行没用,它必须和 proxy_set_header Connection "upgrade" 一起出现,且 proxy_http_version 必须设为 1.1。Nginx 默认用 HTTP/1.0 转发,而协议升级(101 Switching Protocols)只在 HTTP/1.1 中定义。
-
proxy_http_version 1.1是前提,否则后端根本收不到 Upgrade 头 -
$http_upgrade是 Nginx 内置变量,只在客户端带Upgrade头时才有值,否则为空字符串 -
Connection "upgrade"必须写死双引号内的upgrade,不能写成$connection_upgrade变量(除非你额外配了map块) - 如果后端是 Node.js 的
ws或 Python 的websockets,它们对这两个头是否严格匹配很敏感
proxy_read_timeout 和 proxy_send_timeout 必须调大
WebSocket 是长连接,心跳间隔通常几十秒到几分钟。Nginx 默认 proxy_read_timeout 是 60 秒,一旦后端 60 秒没发数据,Nginx 就主动断开连接,导致前端收到 1006 错误。
- 建议设为
proxy_read_timeout 3600;(1 小时),足够覆盖大多数心跳+业务空闲场景 -
proxy_send_timeout同理,也设为3600;,避免 Nginx 在发送响应时因等待超时中断 -
proxy_connect_timeout可保持默认60s,它只影响 Nginx 连后端的建连阶段 - 注意:这个超时是 *单次读/写操作* 的等待时间,不是整个连接生命周期
SSL 配置里容易被忽略的两个细节
WSS 不只是“开了 HTTPS 就行”,Nginx 的 SSL 上下文必须允许 WebSocket 握手通过,否则会在 TLS 层就失败。
-
ssl_protocols TLSv1.2 TLSv1.3—— 必须禁用 TLSv1.1 及更早版本,旧协议不兼容 WebSocket 升级机制 -
ssl_prefer_server_ciphers on—— 某些后端(如 Java Spring WebFlux)依赖服务端选择加密套件来协商 ALPN,关掉它可能导致握手失败 - 证书路径要绝对路径,且 Nginx 主进程(非 worker)必须有读取权限;私钥不能带密码,否则启动会卡住
- 如果用 Let's Encrypt,确保
.well-known/acme-challengelocation 不被 WebSocket location 覆盖
真正让 wss 稳定跑起来的,往往不是加了什么,而是删掉了什么——比如删掉 location 块里多余的 try_files、rewrite 或缓存指令。WebSocket 流量不能走静态文件逻辑,也不能被 gzip 压缩(部分实现会出错)。配置改完别忘了 nginx -t 校验,再 nginx -s reload,别直接 kill 进程。











