JumpServer WebSocket 连接失败排查指南:Nginx 代理配置三步修复法

JumpServer WebSocket 连接失败排查指南:Nginx 代理配置三步修复法

【免费下载链接】JumpServer 广受欢迎的开源堡垒机 【免费下载链接】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

JumpServer WebSocket 连接失败排查场景图

这个"内外有别"的现象本身就暴露了问题方向:应用后端工作正常,出问题的是流量路径。内网访问直连或只经过一层简单转发,外网访问则往往经过 DNS、多级 Nginx、可能还有 CDN,任何一个环节处理不当,WebSocket 都会在握手阶段夭折。

二、追根溯源:WebSocket 握手在代理层经历了什么

要理解修复原理,先补一点前置知识。普通 HTTP 请求是无状态的短连接,而 WebSocket 是一条需要长期保持的双向通道。它之所以能"从普通请求升级成持久连接",靠的是握手阶段的两件头信息:

  1. Upgrade: websocket —— 告诉服务端"我想升级协议";
  2. Connection: Upgrade —— 告诉双方"这个连接要被改造成新协议"。

麻烦之处在于:Nginx 默认的 Connection 头是 close,也就是说,它天然会丢弃升级请求的意图。请求经过代理层时,如果配置里没有显式放行这两个头,握手就被悄悄掐断了——浏览器自然收到 "WebSocket connect failed"。

一句话总结原理:Nginx 不是不支持 WebSocket,而是默认配置会吃掉升级头,必须手动告诉它"保留并传递"

三、排查路线图:三步定位问题出在哪一层

动手改配置之前,先花几分钟把故障范围圈定,避免白忙一场。

第一步:确认报错来自浏览器还是服务端

打开浏览器开发者工具的 Network 面板,过滤出 wswss 类型的请求,观察握手请求的返回码:

  • 101 Switching Protocols:握手成功,问题在别处;
  • 400502426 等:握手被某个环节拒绝,继续往下查;
  • 请求根本没出现:多半是前端 URL 拼接或证书问题。

第二步:用简单工具直连后端验证

在服务器本地直接对 WebSocket 端点发起握手测试,跳过所有代理。若本地直连握手成功,即可坐实问题出在 Nginx 等中间层;若本地也失败,则要回头检查 JumpServer 自身配置(如 wssws 开关、端口监听)。

第三步:逐层审视 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.1WebSocket 升级依赖 HTTP/1.1,默认的 1.0 无法承载
UpgradeConnection 两行把客户端的升级意图原样转发给后端,这是能否握手成功的核心
HostX-Real-IPX-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 加速

如果入口做了 httphttps 的 301 跳转,或套了 CDN,要确认跳转层和 CDN 都支持并转发 wss 流量。部分 CDN 对 WebSocket 支持有限,必要时可考虑对终端连接域名做直连绕过。

六、避坑清单与结果验证

对照下面这份清单逐项检查,能覆盖九成以上的失败案例:

  • 每一级 Nginx 是否都包含 UpgradeConnection "upgrade" 两行;
  • 修改配置后是否执行了 reload(重载而不是重启服务进程);
  • HTTPS 终止层是否正确传递 X-Forwarded-Proto
  • 容器部署时是否同时检查了容器内外的两份 Nginx 配置;
  • 浏览器端是否存在过期的 Service Worker 或强缓存,建议无痕窗口再测一次。

完成修改并重载后,回到浏览器刷新页面,重新打开一个 Web 终端会话:

  • 终端窗口能正常建立,输入命令有实时回显,说明 WebSocket 已恢复;
  • Network 面板里握手返回 101,即为最终成功标志。

七、写在最后

JumpServer WebSocket 连接失败这类问题,成因往往不在应用层,而在网络链路对协议升级的处理方式上。只要理解了 WebSocket 握手原理,学会逐层检查 Nginx 的 UpgradeConnection 头配置,就能以不变应万变,从容应对单层、多级乃至容器化部署下的各种变体。建议把本文的配置模板存为团队内部的部署规范,新环境上线时直接套用,把这类故障扼杀在配置阶段。

【免费下载链接】JumpServer 广受欢迎的开源堡垒机 【免费下载链接】JumpServer 项目地址: https://gitcode.com/feizhiyun/jumpserver

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值