常见问题排查
August 26, 2026 · View on GitHub
🧭 ← 返回 README · 部署教程:deployment · 硬隔离:hard-isolation
按「现象 → 根因 → 修法」组织,都是实际部署中踩过的坑。
502:启动 DSH 后打开是 Bad Gateway
- 现象:桌面显示「运行中」,但打开 DSH(子域名)返回 502(nginx)。
- 根因:子 DSH 没在编排服务分配的回环端口上监听——要么还在冷启动,要么 spawn 即崩。
- 排查:
ps aux | grep dsh # 有没有子进程 ss -tulpn | grep <端口> # 有没有监听 - 冷启动:真实 DSH 冷启动 ~4s(源码启动)。编排服务在
spawn事件就标「running」,但端口要等插件树 boot 完才绑。等 10 秒再开 / 再查ss。 - spawn 即崩:看编排服务终端的子进程 stderr(stderr 会被 pipe 过去)。常见:
--port改动没部署(→ EADDRINUSE)、缺DEEPSEEK_API_KEY等。
启动 DSH 报 spawn dsh ENOENT
- 现象:
/api/dsh/status显示status: "crashed"、lastError: "spawn dsh ENOENT";ps里没有任何 dsh 子进程;再点启动报「已有运行中的 DSH」(崩溃循环留下的残留)。 - 根因:systemd 的 PATH 精简,
dsh(只装在 nvm 下)解析不到。dsh脚本内部也是#!/usr/bin/env node,同样需要 nvm 在 PATH。 - 修法:
- env 里
DSH_SERVER_LOGIN_DSH_BIN=/root/.nvm/versions/node/v22.23.2/bin/dsh(绝对路径,版本按ls ~/.nvm/versions/node/改)。 - systemd 单元加
Environment=PATH=/root/.nvm/versions/node/v22.23.2/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin。 systemctl daemon-reload && systemctl restart dsh-server-login,再先 stop 再 launch。
- env 里
编排服务起不来:better-sqlite3 报 ERR_DLOPEN_FAILED / ABI 版本不匹配
- 现象:
journalctl -u dsh-server-login里ERR_DLOPEN_FAILED、was compiled against ... NODE_MODULE_VERSION ... This version requires ...;systemd 反复重启失败。 - 根因:
npm install用 nvm Node 编译了better-sqlite3原生模块,但 systemd 的ExecStart=/usr/bin/env node解析到另一个 Node 版本,ABI 对不上。 - 修法:
ExecStart用 nvm node 绝对路径(如/root/.nvm/versions/node/v22.23.2/bin/node lib/cli.js),并npm rebuild better-sqlite3用同一个 node。
端口冲突:子 DSH 和编排服务抢 3080
- 现象:手动跑
dsh web报EADDRINUSE 0.0.0.0:3080。 - 根因:编排服务默认绑 3080,子 DSH(harness)默认也绑 3080。
- 关键机制(读 harness 源码确认):harness 的 web 服务端口读
--port这个 CLI flag(web-startup插件解析 →webStartup服务 → webserver),不是 env、不是 patch。--cwd也不是合法 flag。 - 修法:spawn 子 DSH 用
dsh --profile web --host 127.0.0.1 --port <随机端口>(已内置)。
404:打开 DSH 后静态资源全 404
- 现象:HTML 能加载,但
/assets/*、/favicon.svg、/manifest.webmanifest全 404;manifest从域名根去取。 - 根因:DSH 的 SPA(Vite)资源用绝对路径(
/assets/*、/api/*),假设自己挂在域名根/。子路径/u/<id>/dsh/*下,这些绝对路径会打到域名根 → 404;连/api也会打到编排服务自己的 API。子路径方案与这个 SPA 从根上不兼容。 - 修法:改每用户子域名
<用户名>.<baseDomain>,SPA 挂在自己域名根,绝对路径天然成立(含 HTTP 与 WebSocket 均已由编排服务转发)。
403:DSH 功能请求报 transport failure / HTTP 403(如 /api/settings.describe)
- 现象:DSH 页面能加载,但功能 API(
/api/settings.describe、/api/host.describe等)返回 403,前端报 "transport failure for /api/xxx: HTTP 403"。 - 根因:harness 的
/api浏览器信任栅栏(api-request-trust.ts)检查 Origin——origin.host必须等于host.host。代理把host改成 loopback(127.0.0.1:port)却原样转发了浏览器的origin(子域名)→ 不匹配 → 403。 - 修法:代理到 DSH 时剥掉
origin/referer/sec-fetch-*/x-forwarded-*,只保留 loopbackhost(已内置在 proxy.ts 的buildUpstreamHeaders)。
ERR_SSL_VERSION_OR_CIPHER_MISMATCH
- 根因:子域名没有覆盖它的证书(只有主域单域证书)。
- 修法:DNS 通配 + 通配证书(DNS challenge):
certbot certonly --dns-cloudflare -d '*.dsh.example.com' -d 'dsh.example.com'
401:子域名/接口返回 {"error":"unauthorized"}
- 根因:session cookie 是 host-only(没带
Domain),到不了子域名;或浏览器里还是改配置之前登录的旧 cookie。 - 修法:
- 设
DSH_SERVER_LOGIN_COOKIE_DOMAIN=.dsh.example.com(注意前导点),重启。 - 重新登录拿带
Domain的新 cookie。
- 设
登录后跳管理员界面、无法保持登录
- 现象:登录后按 admin 角色跳到
admin.html,但 admin.html 又弹登录框、再登不上。 - 根因:浏览器里存的是旧 cookie(改
Domain/Secure之前登录的),不再匹配当前配置。 - 修法:删掉浏览器里的
sidcookie(DevTools → Application → Cookies → 删除dsh.example.com域下的sid)重新登录。或本地测试时unset DSH_SERVER_LOGIN_COOKIE_DOMAIN DSH_SERVER_LOGIN_SECURE_COOKIES让 cookie 回到 host-only + 非 Secure。
nginx 把 Host 头改成了 upstream 名
- 现象:编排服务日志里
host: dsh_orchestrator。 - 根因:nginx 默认
proxy_set_header Host $proxy_host(upstream 名)。 - 修法:在 location 里加
proxy_set_header Host $host(子域名路由依赖真实 Host 头)。
编排服务日志在哪
- 有 systemd 单元:
journalctl -u dsh-server-login -f。 - 手动跑(
node lib/cli.js):日志(含子 DSH 的 stdout/stderr,已被 pipe)在那个终端里。
SEO 警告:<html lang> / <title> / viewport 缺失
- 现象:Lighthouse 报这三条。
- 根因:来自 DSH 自己的聊天界面 SPA(harness 前端),不是本插件页面(本插件的 login/desktop/admin 都写了这些)。
- 处理:无害、不影响功能。要修需改 harness 前端或由 runtime 插件
tapIndex注入,暂缓。