群晖相关
dsh 公网访问时“工作区加载不出来”排查实录:都是 WebSocket 惹的祸
dsh 公网访问时"工作区加载不出来"排查实录:都是 WebSocket 惹的祸
> 前置阅读:群晖 Docker 部署 DeepSeek Harness(dsh)完整教程
现象
在群晖 Docker 里部署了 DeepSeek Harness(
dsh),局域网访问一切正常,但一旦从公网域名(比如 https://你的域名.com,经 NPS 隧道 + 群晖 DSM 反向代理)访问时,出现:- 页面能打开,登录也正常;
- 但侧边栏工作区列表一直是空的,点"选择工作区"目录也列不出来;
- 浏览器控制台报
transport failure for /api/...: HTTP 403或 WebSocket 连接失败。 - 浏览器安全上下文 →
crypto.randomUUID is not a function - dsh 的
/api信任栅栏 → HTTP 403 - 反向代理不转发 WebSocket → HTTP 426 Upgrade Required(本篇重点)
排查结论(先给答案)
这类问题通常不是 dsh 本身坏了,而是三层各自的安全/转发机制在拦,按顺序排查:
第一层:crypto.randomUUID 报错
现象:局域网 IP 用明文 HTTP 访问时,点"选择工作区"报:
crypto.randomUUID is not a function
原因:这个浏览器 API 只在安全上下文(HTTPS 或 localhost)里存在,明文 HTTP + 局域网 IP 不满足。
解决:
sub_filter 往页面里注入一个 UUID v4 补丁(dsh 场景下可用),普通 HTTP 也能用。第二层:/api 信任栅栏 403
现象:换了个新域名访问后,工作区/目录接口全部
HTTP 403,但页面能开。原因:dsh 出于防 DNS rebinding / 跨站请求的安全考虑,
/api 只接受它认可的 Host(回环地址、部署 IP、或显式登记的 --trusted-host)。新域名不在名单里就被拒。解决:启动 dsh 时把域名加进白名单:
dsh web --host 127.0.0.1 --port 3080 \
--trusted-host 你的域名.com \
--trusted-host 你的公网IP:3080
注意:
--trusted-host 只接受 host 或 host:port 的规范写法,端口写法必须与浏览器访问的一致。第三层:反向代理不转发 WebSocket(本篇重点)
现象特征
页面 200、普通接口 200,但浏览器里 dsh 的实时数据(工作区/会话列表)永远加载不出来。用命令行模拟 WebSocket 升级一眼就能定位:
curl -i \
-H "Connection: Upgrade" \
-H "Upgrade: websocket" \
-H "Sec-WebSocket-Version: 13" \
-H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
https://你的域名.com/api/events.mux
如果返回:
HTTP/1.1 426 Upgrade Required
Server: nginx
就是反向代理把 WebSocket 升级请求拦了。
为什么会这样
dsh 的 Web UI 靠两条 WebSocket 通道(
/api/events.mux、/api/events.host)实时推送工作区/会话数据。普通 HTTP(S) 反向代理如果不带以下转发头,浏览器发起的 Upgrade: websocket 请求就不会被代理给后端:proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
特别是群晖 DSM 自带的反向代理(控制面板 → 登录门户 → 反向代理)默认不带这两行,这是它的已知短板。
解决办法
#
方案 A:给反向代理加 WebSocket 转发头(DSM 实测有效)
SSH 登录群晖,编辑 DSM 的 nginx 配置(改前先备份):
sudo cp /usr/local/etc/nginx/sites-enabled/server.ReverseProxy.conf \
/usr/local/etc/nginx/sites-enabled/server.ReverseProxy.conf.bak
在对应域名的
location / { } 块里加上:proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
然后测试并重载:
sudo nginx -t
sudo nginx -s reload
改完刷新页面,工作区列表就出来了。
> ⚠️ 注意:DSM 界面里如果再修改反向代理设置,它会重新生成配置、覆盖手工修改,需要重新加这两行。
#
方案 B:换一个支持 WebSocket 的入口
架构备注:NPS 隧道是透明的
排查过程中容易误判"NPS 是不是不支持 WebSocket"。NPS 的 TCP 隧道是纯透明转发,WebSocket 可以原样穿过(用 NPS 直连隧道入口实测升级是
101 Switching Protocols)。所以:只要 426 出现在"带域名反代"的路径上,问题一定在反代层,不在 NPS。
快速自检清单
| 现象 | 原因 | 处理 |
|---|---|---|
crypto.randomUUID is not a function | 非安全上下文 | HTTPS 访问,或注入补丁 |
/api 全部 403 | 域名不在信任白名单 | 加 --trusted-host |
| WebSocket 426 | 反代不带转发头 | 加 Upgrade/Connection 两行 |
| 一切正常但列表空 | 工作区还没创建会话 | 先"选择工作区"选目录开个会话 |
小结
dsh 这类"页面能开、数据不来"的问题,九成是反向代理把 WebSocket 拦了。用一条
curl 模拟升级请求就能快速区分是 403(信任栅栏)还是 426(反代不支持 WS),对症下药,十分钟收工。
评论(0)