dsh-lan-guard
把官方 DSH Web UI 安全地开放到局域网:不改动 DSH 自身的回环绑定,另开一个带密码门禁、自签 HTTPS 与可逐个吊销的设备配对的反向代理端口,并提供手机扫码入口。
安装
dsh plugin --profile web add dsh-lan-guard
沙箱测试结果
| 阶段 | 结果 |
|---|---|
| 1 安装 | ✓ |
| 2 列装 | ✓ |
| 3 挂载 | ✓ |
| 4 启动 | — |
四阶段在隔离沙箱里跑:安装(有网)→ 列装 → 挂载 → 启动(后三步断网)。
README
<h1 align="center">DSH LAN Guard</h1>
<p align="center">把桌面 DSH 的官方 Web 界面安全地开放到局域网:带门禁的反向代理 + 默认自签 HTTPS + 手机扫码入口。DSH 自身的回环监听与官方 UI 零改动。</p>
<p align="center">
<a href="https://github.com/idoall/dsh-lan-guard/actions/workflows/ci.yml"><img src="https://github.com/idoall/dsh-lan-guard/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
<a href="https://www.npmjs.com/package/dsh-lan-guard"><img src="https://img.shields.io/npm/v/dsh-lan-guard?label=npm&color=CB3837" alt="npm 版本"></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-0F172A" alt="MIT"></a>
<img src="https://img.shields.io/badge/DSH-0.2.2--rc.1-4B6BFB" alt="DSH 0.2.2-rc.1">
</p>
<p align="center"><a href="README.md">English</a> | 中文</p>
<p align="center">
<a href="#能做什么">能做什么</a> ·
<a href="#快速开始">快速开始</a> ·
<a href="#设置">设置</a> ·
<a href="#兼容性">兼容性</a> ·
<a href="#安全边界">安全边界</a> ·
<a href="#排障">排障</a> ·
<a href="CHANGELOG.md">更新记录</a>
</p>
DSH LAN Guard 是 DeepSeek Harness 社区插件。它只注册官方设置页里的一个区块(settings.section),不替换任何官方布局,也不修改 DSH 源码或 DSH 自身的监听绑定。
DSH 的 Web 界面只监听 127.0.0.1,而官方明确拒绝绑定 0.0.0.0。本插件不碰那个绑定,而是在另一个端口上再开一个带门禁的监听,把官方界面原样代理出去:密码门禁、默认自签 HTTPS、手机扫码入口,以及可逐个批准与拉黑的设备配对。装完重启一次即可用——不需要手写任何配置。
<p align="center">
<img src="./assets/settings-access.png" width="78%" alt="设置 → 局域网访问 → 扫码访问:运行中状态、免密链接与可扫描二维码">
</p>
能做什么
- 门禁反向代理:完整转发 HTTP 与 WebSocket(含官方界面的
/api/remote.mux长连接),改写Host/Origin,剥离逐跳头,上游不可达时返回502。DSH 自身的绑定与配置一动不动。 - 默认对外可用,但对外可达 ≠ 可以进入:默认监听
0.0.0.0,所以安装后只需重启一次就能用;门禁默认开启,未设访问密码时拒绝所有设备,且默认自签 HTTPS——不存在明文传输。想只在本机使用,在设置页切到「仅本机」即可。 - 双密码门禁:PBKDF2-SHA256(600,000 次迭代)。访问密码给手机等访客设备登录用,管理密码用于解锁本设置页的管理台(未设置时退回访问密码);另有
dsh_免密链接、持久访客会话、按 IP 锁定与 CSRF 校验。 - 默认自签 HTTPS,CA 身份跨重启不变:自动生成
DSH LAN Guard CA,按所选网卡地址签发叶证书。换 IP 只重签叶证书,所以每台设备只需信任一次。 - 本机永不锁定:直连
127.0.0.1享有物理免锁特权(能用这台电脑的人本就能改这些设置);远程访问按adminPolicy处理——只读(默认)、需密码解锁、或不锁。 - 设备配对与身份拉黑:手机首次通过门禁时命名,获得 HttpOnly 设备身份 cookie,出现在 已授权设备 里(名称 / 创建时间 / 最近使用 / 来源 IP),可逐个吊销或拉黑该身份。拉黑持续作用于已记录身份,不等于封禁物理设备:换浏览器或清除 cookie 后,仍可用共享访问密码重新配对。需要审核重新配对时,请开启新设备批准。
- 设置挂在官方设置页内:「局域网访问」分区含四个 tab——扫码访问、安全认证、已授权设备、连接与证书。排版与配色全部使用官方设计 token,不替换任何官方布局。
- 远程也能添加工作区(智能分流):DSH 的目录选择器在启动时判定一次,本机回环绑定 + 有显示器会判成「原生」——手机点「添加工作区」实际是在电脑屏幕上弹文件夹对话框。本插件在浏览器侧以更低优先级遮蔽官方选择流程:本机浏览器照旧走系统原生对话框,远程设备改用页面内目录浏览器(面包屑、快捷入口、目录列表)。选中后仍由 DSH 官方工作区流程登记,插件只读目录、不写任何东西。
- 端口与监听范围可配:默认
3081(DSH 端口 + 1),被占用时自动往后顺延(最多试 10 个);设置页可改端口并带可用性检查,也可在「局域网(默认)/ 仅本机」之间切换(两者都需重启 dsh 生效)。 - 可选 mDNS:默认关闭;开启后广播
_dsh-lan-guard._tcp。 - 升级检测:设置页显示「当前版本 → npm 上最新版本」并给出可复制的升级命令;插件不会自己安装或重启任何东西。
快速开始
环境要求:
- 带 Web profile 的 DeepSeek Harness
- Node.js 20 或更新
- 已验证的 DeepSeek Harness:
0.2.2-rc.1(接口审查、新版依赖类型检查与自动回归;另在运行 rc.1 的实例上只读核对代理入口、页面注入与管理接口。本次未重新进行 rc.1 浏览器交互、完整 LAN/WebSocket 与手机实机验收;alpha.3 的浏览器测量属于上一版验证)。 - 2026-11-04 核对 npm 渠道:
next为0.2.2-rc.1,alpha为0.2.2-alpha.3,latest为0.2.1-rc.5。本次验证0.2.2-rc.1;0.2.1-rc.5不在已验证清单内。
从 npm 安装:
dsh plugin --profile web add dsh-lan-guard@latest
从 GitHub 安装:
dsh plugin --profile web add "github:idoall/dsh-lan-guard"
从本地克隆安装:
git clone https://github.com/idoall/dsh-lan-guard.git cd dsh-lan-guard pnpm install && pnpm run build dsh plugin --profile web add "link:$(pwd)"
然后重启一次 DSH,打开 设置 → 局域网访问。重启后插件已经在对外监听(默认 0.0.0.0:3081,自签 HTTPS + 门禁),你只需要:
1. 在 安全认证 里设置访问密码(至少 8 位)。没设之前,门禁拒绝所有设备。
2. 在 连接与证书 确认监听范围(默认「局域网」),并选择对外公布的网卡——网卡决定二维码/访问地址用哪个 IP、自签证书签哪些地址。
3. 在 扫码访问 扫码,手机上信任一次 DSH LAN Guard CA、输入访问密码、给设备命名。之后手机运行的就是官方 DSH 界面。
远程设备默认是只读的(adminPolicy: local_only):能用 DSH,但不能改插件设置。想让手机也能管理,在桌面把策略改掉。
设置
设置项集中在 设置 → 局域网访问 的四个 tab 里。非敏感开关(enabled、listenPort、listenHost、networkInterface、settingsUnlock、answerHeartbeat、socketWatchdog、mobileCompat、mobileScrollFix、mobileTurnRail、auth.mode、auth.adminPolicy、auth.adminProtection、auth.allowLoopback、auth.requirePairing、auth.requireApproval)可直接改;listenPort 与 listenHost 需重启 dsh 生效;settingsUnlock / socketWatchdog / mobileCompat / mobileScrollFix / mobileTurnRail 刷新页面即可生效,answerHeartbeat 立即对已打开的连接生效;dataDir 与 tls.* 属启动期字段,需在 profile patch 里改。
设置项 · 默认 · 作用
监听范围 · 局域网 0.0.0.0 · 决定局域网能否访问这个端口。切到「仅本机 127.0.0.1」更保守,需重启 dsh。两种选择都保留门禁与自签 HTTPS。
代理端口 · 3081 · DSH 端口 + 1;被占用时自动往后顺延(最多试 10 个),带可用性检查。需重启 dsh。
对外公布的网卡 · 自动选择 · 决定二维码/访问地址用哪个 IP、自签证书签哪些地址;虚拟网卡会被降权标注。
验证模式 · 扫码免密 + 密码 · 也可选「仅密码」或「仅安全 Token」。切换会吊销所有已有访客会话。
访问密码 · 未设置 · 手机等访客设备的登录密码。未设置时门禁拒绝所有设备。
管理密码 · 未设置 · 解锁本设置页的管理台;未设置时退回访问密码。
本机回环访问免密 · 开 · 127.0.0.1 直连跳过门禁(物理免锁)。
远程设备管理权限 · 仅本机 · 决定局域网设备能否管理:「仅本机」只读;「密码解锁」需先解锁;「不锁定」不额外要求。远程浏览目录并添加工作区需要后两者之一。
管理操作需要先解锁 · 开 · 关闭后,符合策略的远程会话可直接修改设置(local_only 除外,它永远只允许本机)。
局域网设备可用官方设置页 · 开 · DSH 官方设置面默认只对回环页面开放,局域网设备打开「设置 → 模型」会提示 settings are unavailable in this browser。开启后,通过门禁的设备(含手机)刷新页面即可使用官方设置页;这是界面解锁,不是新增权限——设置接口本来就只由门禁把关,读取密钥仍由 DSH 脱敏。刷新页面生效,无需重启。
代理代答心跳 · 开 · DSH 每 2 秒给每条 WebSocket 发心跳,连续两次没被回应就断开(实测 6 秒)。手机锁屏/切走时页面被系统挂起、回不了心跳,于是只走 WebSocket 的会话记录就会「载入不全、甚至断开」。开启后由代理替手机回心跳,手机自己回的那次是重复包,无副作用。立即生效(含已打开的连接)。
断线看门狗 · 开 · 页面补丁:卡在「连接中」超过 8 秒的 WebSocket 会被关掉;从后台回来 10 秒后仍一条都没连上时自动重载一次(每标签最多连续 3 次,冷却 20 秒起)。只对真的连不上的页面生效。刷新页面生效。
移动端兼容垫片 · 开 · 页面补丁:补 AbortSignal.any/AbortSignal.timeout/Promise.withResolvers/Iterator 与移动端 meta。缺这些 API 时 DSH 客户端在会话流里抛错,界面只会一直显示「载入历史…」且没有报错。现代浏览器上这些分支不生效。刷新页面生效。
手机滚动矫正(窄屏) · 开 · 手机端 DSH 外壳在窄屏下把对话列裁在 overflow:hidden 的层里(实测 844/1688),整页也不可滚 → 内容可见但滑不动。开启后只在「窄屏 + 移动端 + 整页不可滚 + 找到被裁剪溢出的层」四条同时成立时,把那几层改成可触摸滚动;正常页面不碰。页面加 ?lgdiag=1 可看布局诊断。刷新页面生效。
手机端轮次导航 · 关 · 把 PC 右侧那根轮次浮轨搬到手机:DSH 在手机上其实照样渲染它(可跳转到某一轮、未加载的会先翻历史再跳、当前轮次跟随),只是被它自己的窄屏容器查询藏了起来(@container (max-width: 900px))。开启后用一段只在 ≤1023px 生效的样式把它放出来(right:4px、宽 28px,正好占满对话区右侧留白、不压正文),并给手机补一套手势:轻点 = 跳转、按住 ≈0.3 秒 = 弹出可读的轮次卡片(含该轮提问与回
…(truncated)
以上内容来自 npm 上的 README,我们只做格式化,不改内容。
版本
npm 上共发布:28,最后更新 2026-11-04