JumpServer WebSocket 连接失败排查指南:Nginx 代理配置三步修复法
【免费下载链接】JumpServer 广受欢迎的开源堡垒机 项目地址: https://gitcode.com/feizhiyun/jumpserver
不少管理员在部署 JumpServer 堡垒机后遇到过这样的怪事:同一套系统,用 IP 加 HTTP 从内网访问一切正常,可一旦换成 HTTPS 域名从外网访问,页面虽然能打开,却一直弹 "WebSocket connect failed, please check network" 的红色提示。这个问题在 JumpServer WebSocket 连接失败的众多案例中占比极高,而绝大多数情况下,罪魁祸首并非 JumpServer 本身,而是链路上一处或多处 Nginx 代理没有为 WebSocket 做好放行准备。下面这份排查思路,会带你从现象一路走到 Nginx WebSocket 代理配置的落地修改,彻底告别这个报错。
一、先看懂现象:为什么内外网表现截然不同
故障发生时,往往有几个典型特征同时出现:
- 内网通过
http://内网IP:端口访问,SSH 会话、Web 终端都正常; - 外网通过
https://域名访问,页面能加载,但终端窗口、文件传输等功能异常; - 浏览器开发者工具(F12)的 Console 区域能看到 WebSocket 握手失败,状态码通常为
400或直接显示failed。
这个"内外有别"的现象本身就暴露了问题方向:应用后端工作正常,出问题的是流量路径。内网访问直连或只经过一层简单转发,外网访问则往往经过 DNS、多级 Nginx、可能还有 CDN,任何一个环节处理不当,WebSocket 都会在握手阶段夭折。
二、追根溯源:WebSocket 握手在代理层经历了什么
要理解修复原理,先补一点前置知识。普通 HTTP 请求是无状态的短连接,而 WebSocket 是一条需要长期保持的双向通道。它之所以能"从普通请求升级成持久连接",靠的是握手阶段的两件头信息:
Upgrade: websocket—— 告诉服务端"我想升级协议";Connection: Upgrade—— 告诉双方"这个连接要被改造成新协议"。
麻烦之处在于:Nginx 默认的 Connection 头是 close,也就是说,它天然会丢弃升级请求的意图。请求经过代理层时,如果配置里没有显式放行这两个头,握手就被悄悄掐断了——浏览器自然收到 "WebSocket connect failed"。
一句话总结原理:Nginx 不是不支持 WebSocket,而是默认配置会吃掉升级头,必须手动告诉它"保留并传递"。
三、排查路线图:三步定位问题出在哪一层
动手改配置之前,先花几分钟把故障范围圈定,避免白忙一场。
第一步:确认报错来自浏览器还是服务端
打开浏览器开发者工具的 Network 面板,过滤出 ws 或 wss 类型的请求,观察握手请求的返回码:
101 Switching Protocols:握手成功,问题在别处;400、502、426等:握手被某个环节拒绝,继续往下查;- 请求根本没出现:多半是前端 URL 拼接或证书问题。
第二步:用简单工具直连后端验证
在服务器本地直接对 WebSocket 端点发起握手测试,跳过所有代理。若本地直连握手成功,即可坐实问题出在 Nginx 等中间层;若本地也失败,则要回头检查 JumpServer 自身配置(如 wss 与 ws 开关、端口监听)。
第三步:逐层审视 Nginx 配置
从最外层入口往里数,每一处 location 块都要确认是否具备 WebSocket 代理能力。这一步和下一步是同一件事的两面,排查的同时也顺手完成了修复。
四、动手修复:Nginx WebSocket 代理配置完整示例
在 JumpServer 的前置 Nginx 配置中,为 WebSocket 请求单独编写(或合并进既有)的 location 块大致长这样:
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
逐行拆解,每一行都有明确职责:
| 配置项 | 作用 |
|---|---|
proxy_http_version 1.1 | WebSocket 升级依赖 HTTP/1.1,默认的 1.0 无法承载 |
Upgrade 与 Connection 两行 | 把客户端的升级意图原样转发给后端,这是能否握手成功的核心 |
Host、X-Real-IP、X-Forwarded-* | 还原真实客户端 IP 与协议信息,JumpServer 依赖它们做会话审计与权限判定 |
proxy_read/send_timeout | 拉长读写超时,避免长时间空闲的 WebSocket 连接被代理掐断 |
改完后执行 nginx -t 检查语法,再 systemctl reload nginx 平滑重载即可生效。
五、多场景适配:这些部署形态最容易踩坑
修复不是"抄一段配置"那么简单,不同部署方式各有需要注意的细节。
场景一:单层 Nginx 反向代理
最常见也最简单,套用上面的配置块即可。注意把 proxy_pass 指向 JumpServer 实际监听地址,如果 HTTPS 终止在这一层,务必保留 X-Forwarded-Proto,否则 JumpServer 会误判协议,拼接出错误的 WebSocket 地址。
场景二:多级代理层层嵌套
企业网络里常有"防火墙 → 接入 Nginx → 业务 Nginx"这类多级结构。请记住一条铁律:WebSocket 升级头在每一层都会被丢弃一次,所以每一层都要单独配置。只改最外层、内层保持默认,故障依旧,这是排查时最容易忽视的死角。
场景三:Docker 容器部署 JumpServer
使用 Docker Compose 部署时,容器网络里同样有内置 Nginx 在监听端口。除了检查宿主机上的代理,还要进入容器确认内部 Nginx 配置是否放行了 WebSocket 头。很多案例中,宿主机配置无误,问题恰恰藏在容器内部这一环。
场景四:域名跳转与 CDN 加速
如果入口做了 http 到 https 的 301 跳转,或套了 CDN,要确认跳转层和 CDN 都支持并转发 wss 流量。部分 CDN 对 WebSocket 支持有限,必要时可考虑对终端连接域名做直连绕过。
六、避坑清单与结果验证
对照下面这份清单逐项检查,能覆盖九成以上的失败案例:
- 每一级 Nginx 是否都包含
Upgrade与Connection "upgrade"两行; - 修改配置后是否执行了
reload(重载而不是重启服务进程); - HTTPS 终止层是否正确传递
X-Forwarded-Proto; - 容器部署时是否同时检查了容器内外的两份 Nginx 配置;
- 浏览器端是否存在过期的 Service Worker 或强缓存,建议无痕窗口再测一次。
完成修改并重载后,回到浏览器刷新页面,重新打开一个 Web 终端会话:
- 终端窗口能正常建立,输入命令有实时回显,说明 WebSocket 已恢复;
- Network 面板里握手返回
101,即为最终成功标志。
七、写在最后
JumpServer WebSocket 连接失败这类问题,成因往往不在应用层,而在网络链路对协议升级的处理方式上。只要理解了 WebSocket 握手原理,学会逐层检查 Nginx 的 Upgrade 与 Connection 头配置,就能以不变应万变,从容应对单层、多级乃至容器化部署下的各种变体。建议把本文的配置模板存为团队内部的部署规范,新环境上线时直接套用,把这类故障扼杀在配置阶段。
【免费下载链接】JumpServer 广受欢迎的开源堡垒机 项目地址: https://gitcode.com/feizhiyun/jumpserver
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考




