前言¶
DSH 的 Web UI 长期只有进程级 ?token=:每次重启换一次,得从终端抄出来,HTTP 反代之后 /api 还容易直接 403。dsh-web-guard(仓库 lvxianchao/dsh-web-guard,维护者 lvxianchao,MIT 许可证)把这几个部署问题收进一个插件:一个访问密码、可吊销会话、原生设置页,以及 TLS。下面介绍它的定位、安装、配置和运维注意事项。
生态背景:DSH 的理念是「一切皆插件」;本文的目录页来自第三方社区站点 SkillHub,与 DeepSeek 官方无从属关系。星标 1、分类 admin-security 为该目录页所载,截至撰写时无其他独立佐证。
它解决什么¶
README 把原生行为与插件行为对比成一张表,四个问题如下:
| 问题 | 原生行为 | dsh-web-guard |
|---|---|---|
| 没有人类登录 | 只有启动时打印的 ?token=,重启就换 |
一个密码 + 可吊销会话 |
| 反代一律 403 | /api 栅栏要求 Host 原样可达,NPM/Caddy 会改写它 |
代理把 Host/Origin 改写成回环 authority |
| token 要挖日志 | 得 journalctl \| grep token 才能进站 |
进程内兑换,浏览器见不到 token |
| 明文 HTTP 报错 | crypto.randomUUID is not a function |
注入 polyfill |
零运行时依赖,只用 Node 标准库;npm 包里是预构建好的 JavaScript,dsh plugin add 不需要工具链。
它怎么工作¶
browser ──HTTP(S)──> dsh-web-guard :3081 ──> DSH listener (loopback)
│
├─ not signed in → /login
├─ signed in → forward, Host/Origin rewritten to loopback
└─ injects the harness cookie (never exposed to the browser)
DSH 的 /api 栅栏接受回环 authority,所以让每个上游请求看起来都来自回环,就消掉了 403。鉴权发生在代理里,不是前端遮罩:没有会话 cookie 的请求到不了 DSH。浏览器半(dsh.client)只负责把管理页挂进 DSH 的设置面板;闸门本身完全在服务端,浏览器半加载失败也不影响使用。
安装与启用¶
三种安装方式,命令来自 README:
# npm
dsh plugin --profile web add @lvxianchao/dsh-web-guard
# from GitHub
dsh plugin --profile web add "github:lvxianchao/dsh-web-guard"
# from a local checkout
dsh plugin --profile web add /path/to/dsh-web-guard
main 分支只放已发布代码(开发在 dev 分支),所以这条命令装到的是最新稳定版。包里声明了 dsh.bundle,guard 行会自动叠加,装完重启 dsh 即可。
首次启动会自动生成一个密码,打印在终端,并以哈希形式存到 <profile>/data/dsh-web-guard.json(0600)。想固定实例,改 ~/.dsh/profiles/web/cordis.patch.yml:
- id: guard
config:
listenHost: '0.0.0.0'
listenPort: 3081
注意 profile patch 会整体替换 config,要保留的键都得重写一遍。
从 v2 升级:右下角浮动盾牌和 /__guard/admin 已移除,管理入口改为「设置 → DSH Web Guard」。重新安装(或升级到 3.0.0)并重启 DSH;密码哈希、会话缓存和设置文件格式不变,升级不踢人。
前提:DSH 自己必须绑回环(默认即 127.0.0.1)。如果绑在局域网 IP 上,客户端可以绕过闸门直连——插件启动时会检测并告警。
典型用法¶
让插件终结 TLS(没有反向代理)¶
config:
listenHost: '0.0.0.0'
listenPort: 8443
tls:
certFile: /path/fullchain.pem
keyFile: /path/privkey.pem
浏览器访问 https://<host>:8443,会话 cookie 自动带 Secure。
放在反代之后¶
反代只做 TLS,上游填 http://<dsh-host>:3081,并开启 WebSocket。不需要任何 Host 改写配置——这正是插件要消掉的部分。
纯局域网¶
明文 HTTP + 密码,最简单也最不安全,会话 cookie 可被嗅探。
常用配置键¶
| 键 | 默认 | 说明 |
|---|---|---|
listenHost |
0.0.0.0 |
闸门监听地址 |
listenPort |
3081 |
闸门端口,不能与 DSH 端口相同 |
password |
— | 明文密码(启动时哈希) |
passwordHash |
— | scrypt$N$r$p$salt$key,优先于 password |
sessionDays |
7 |
会话时长;0 = 关浏览器即失效 |
maxAttempts |
5 |
连续失败次数,超过临时锁定 |
lockMinutes |
5 |
锁定时长 |
polyfill |
true |
注入 crypto.randomUUID 兜底 |
title |
DSH Web Guard |
登录页标题 |
tls |
null |
{certFile, keyFile},启用 HTTPS |
生成 scrypt 哈希:
node -e "import('./lib/auth.js').then(m=>console.log(m.hashPassword(process.argv[1])))" 'your-password'
它是什么,不是什么¶
这是一道「入口」,不是可选插件。装上之后,它监听 3081,请求转给只听回环的 DSH(3080)。插件一旦不加载,3081 就停止监听,内网和外网会同时打不开——而 DSH 本体还在跑,会话和数据都在,只是够不着。如果已经把这地址开放到公网,这一点需要格外当心。
安全模型上要说清楚边界:一个密码、一个权限级别,它不是多用户系统。DSH 的 agent 本身能执行代码,任何登录者都拥有该机器的执行权限——这是产品设计,不是闸门的缺陷。
前面表格里做的事——把 /api 的 403 归因于 Host 被反代改写,以及「代理把 Host 改写成回环 authority 就能放行」——都出自该项目 README 的表述。如果这个模型与你环境里栅栏的实际行为不一致,先查 DSH 官方文档再改配置。
适用场景与注意¶
适合:想把 DSH Web UI 暴露到内网或公网、又不想继续抄 token 的人;已经架好 NPM/Caddy/Traefik、被 /api 403 卡住的人;想用一个原生设置页管理密码与会话的人。
务必注意:
- 不要卸载、也不要禁用它。不要执行
dsh plugin --profile web remove @lvxianchao/dsh-web-guard;不要从 profile 的package.json里删掉dsh.profile.bundles中这一项;也不要在cordis.patch.yml里给它加disabled: true。DSH 的「设置 → 插件」页是只读清单,只有状态标签,没有开关,误关基本发生在命令行。 - 要求 DeepSeek Harness
0.2.2-rc.1或更新(engines.dsh: >=0.2.2-rc.1 <0.3.0),Node>=22.19,许可证 MIT。宿主版本不匹配时整个 bundle 会被跳过——这时是闸门不启动,应该升级 DSH,而不是删掉插件。 - 插件以当前 dsh 进程权限运行,装前应检查源码与许可证。
- 会话表会落盘到
<profile>/data/dsh-web-guard-sessions-<port>.json(0600,临时文件 + rename 原子写入),重启 DSH 不会把已登录浏览器踢下线——但重启不等于吊销,要全部吊销用设置页的「退出所有设备」。
如果不小心关掉了,恢复命令不依赖插件本身:
# 1) 重新装回(本地目录装的就用 file:)
dsh plugin --profile web add file:/path/to/dsh-web-guard
# 或:dsh plugin --profile web add github:lvxianchao/dsh-web-guard
# 2) 重启,3081 会重新监听
sudo systemctl restart dsh-web
如果当初是加了 disabled: true,把那行删掉再重启;密码哈希在 <profile>/data/dsh-web-guard.json,不丢。
真正的坑不在这两条命令,而在于此刻你已经连不上这台机器。闸门只代理 HTTP 入口,不碰 SSH;但如果远程访问都收在这一个域名上,插件一没,只剩一条路——一条不经过它的后路。至少准备一条:宿主控制台(PVE / ESXi / 云厂商 VNC)进容器或虚机执行上面两条命令,或一条独立 SSH 通道(内网直连、跳板机、VPN)。并且在今天、现在就验证它能用,然后把恢复命令抄一份到你能从外面打开的地方。
结尾¶
dsh-web-guard 的价值在于把「抄 token、改 Host、挖日志、明文 HTTP 报错」这四件事收敛成一个插件,代价是它成了唯一的入口——好处和风险都来自这一点。安装前先确认 DSH 版本够新,装后留一条不经过闸门的后路。
目录页:https://www.skillhub.cn/plugins/lvxianchao/dsh-web-guard
GitHub:https://github.com/lvxianchao/dsh-web-guard
npm:https://www.npmjs.com/package/@lvxianchao/dsh-web-guard