@riceawa/dsh-lan-gateway
Publishes the DSH Web GUI to LAN or internet with dsh kept on loopback. Every source must sign in for an HMAC session cookie unless passwordless LAN is opted into. Adds self-signed or custom TLS, a secureCookies override for plaintext-HTTP proxies, and a UUID shim for plain-HTTP origins.
Install
dsh plugin --profile web add @riceawa/dsh-lan-gateway
Sandbox test results
| Stage | Result |
|---|---|
| 1 install | ✓ |
| 2 list | ✓ |
| 3 mount | ✓ |
| 4 boot | — |
Four stages run in an isolated sandbox: install (network on) → list → mount → boot (last three with no network).
README
<p align="center">
<img src="assets/banner.webp" alt="dsh-lan-gateway — 把 DeepSeek Harness 的 Web GUI 安全地开放到局域网 / 公网" />
</p>
<h1 align="center">dsh-lan-gateway — LAN / 公网网关插件</h1>
<p align="center">
<img src="https://img.shields.io/badge/DeepSeek%20Harness-4d6bfe?logo=deepseek&logoColor=fff&style=flat-square" alt="DeepSeek Harness" />
<img src="https://img.shields.io/badge/version-0.8.0-2b7fff?style=flat-square" alt="version 0.8.0" />
<img src="https://img.shields.io/badge/TLS-8b5cf6?logo=lock&logoColor=fff&style=flat-square" alt="TLS" />
<img src="https://img.shields.io/github/license/rice-awa/dsh-lan-gateway?style=flat-square" alt="MIT license" />
<a href="https://awesome-dsh-plugin.com"><img src="https://awesome-dsh-plugin.com/badge.svg" alt="awesome · DSH plugin" /></a>
</p>
dsh web 明确拒绝 --host 0.0.0.0,以免把远程代码执行暴露到网络。本插件的做法是让 dsh 继续只绑 127.0.0.1,另起一个反向代理监听未指定地址(双栈,IPv4 与 IPv6 客户端都可接入),转发到 loopback 端口并改写 Host / Origin。
默认拒绝:loopback、LAN、公网三种来源都要先在网关登录页取得 HMAC 会话 cookie,LAN 免密需要显式打开 lanPasswordless,默认关闭。底座要求 dsh 0.2.0 / 0.2.1 / 0.2.2:engines.dsh 与 @deepseek-ai/dsh-* peer 范围同时声明这三条线,无论底座按哪个字段判定兼容性都能通过;0.1.7 及更早版本不再支持。网关在进程内中继一条共享上游会话,上游自身的授权仍然把关每个请求,网关只决定谁可以使用这条会话。
dsh 0.2.1 的 --host 可以绑定单个本机网卡地址(通配地址仍被拒绝),--tls-cert / --tls-key 可直接提供 HTTPS。网关的定位不变:它负责通配监听、登录门禁与自签名证书,并始终向 127.0.0.1 转发。若改用 dsh 自己的 --host 直接绑定网卡,请关闭网关——两者不要同时使用。
插件另外提供两项功能:
- 不安全源 UUID shim:网关以纯 HTTP 的局域网地址服务页面,浏览器视其为不安全源,不提供
crypto.randomUUID。client bundle 在页面加载早期补一个基于getRandomValues的实现,工作区才能正常打开。 - TLS:自动生成并持久化的自签名证书,或者挂载自行签发的 PEM。自签名证书首次访问会有浏览器警告,属预期行为。
安装
已发布到 npm,安装的是预构建产物,不需要 allowBuilds 授权。可将下面这段话交给你的 agent:
帮我安装 dsh 插件 @riceawa/dsh-lan-gateway,遵循
https://github.com/rice-awa/dsh-lan-gateway/blob/main/INSTALL.md
也可以手动执行:
dsh plugin --profile web add @riceawa/dsh-lan-gateway
dsh plugin ... add 会把参数转发给 profile 目录里的 pnpm。npm 包自带 lib/,不会触发 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED。如果仍然报错,把报错条目写进 ~/.dsh/profiles/web/pnpm-workspace.yaml 的 allowBuilds 后重试,完整步骤见 [INSTALL.md](INSTALL.md#for-agents完整安装流程)。
从源码构建:
git clone https://github.com/rice-awa/dsh-lan-gateway.git cd dsh-lan-gateway pnpm install pnpm build # host → lib/index.js pnpm build:client # client → lib/client.js pnpm test # 216 项
仓库里还有一个 [lan-gateway](skills/lan-gateway.md) 技能,安装后可直接在 dsh 对话里说「设置网关密码为 …」「开启远程访问」,agent 会调用 lan_gateway 工具完成,密码以参数传入,不写入配置,也不回显。改密码也可以不走模型:在本机打开 Plugins 页的「LAN 网关」卡片,直接填两次新密码覆盖(见下「登录密码」)。安装方式见 [INSTALL.md](INSTALL.md#for-agents完整安装流程)。
如需在手机 / 平板上访问,可另外安装 dsh-web-mobile 做移动端 UI 适配:
dsh plugin --profile web add github:mexiaosqwq/dsh-web-mobile
用法
lan_gateway enable # 开启网关(需先满足启动条件,否则给出迁移文案) lan_gateway status # 端口 / 目标 / 密码 / 会话 epoch / 已登出会话数 / 中继状态 / 入口加密方式 / 上次错误 lan_gateway set-password # 设置登录密码(≥8 位,改动会让所有已签发会话立即失效) lan_gateway rotate-secret # 轮换会话密钥,作废全部登录 cookie 与已建立的 WebSocket lan_gateway tls-regenerate # 换发自签名证书(tlsMode=self-signed 时) lan_gateway disable # 关闭
lan_gateway 是模型可调用的工具,上述命令无需手动执行。直接在对话里说「查看网关状态」「设置网关密码为 ……」即可,密码以参数传给模型,不会写入任何配置文件。改密码也可以完全不经模型:在本机 Plugins 页的插件卡片里直接改(见下「登录密码」)。
配置
所有可调项都写在本插件自己的 profile 条目里(dsh ≥ 0.1.7 起,设置写入按条目 id 寻址)。打开侧边栏的 Plugins 页 →「已安装」→ @riceawa/dsh-lan-gateway:本插件的配置就渲染在这个包自己的页面上——挂的是 dsh 给「bundle 自己的配置」声明的 plugins.bundle.config 槽(按包名 @riceawa/dsh-lan-gateway 挂载,与 dsh-mnemon、dshmarket 等插件同一套机制),页面标题、图标与面包屑由 Plugins 页自己绘制。
表单本身是 dsh 的原生设置表单。 字段由平台的 SettingsFormModel / SettingsForm / SettingsValueField 渲染(开关用 Switch,枚举用 SegmentedControl,状态用 Tag),读写走 ctx.configForms.get('dsh-lan-gateway') 这一条与官方插件页相同的、带版本围栏的配置写入通道:改动先在本地暂存,点「保存」才一次性提交,保存后监听器按新配置自动重启。文案注册在自己的 locale 命名空间 dshLanGateway 里,跟随 Settings → Language 切换中英文。
因为写路径换成了 dsh 自己的设置服务,能用 dsh 的浏览器就能改网关配置——包括经网关访问的 LAN / 公网浏览器(它们骑的是同一条共享上游会话)。这与 0.7.x 及更早的「只有宿主机回环能写」不同,是改用原生表单的直接代价,见「安全模型」。登录密码仍然只走宿主机回环(见下「登录密码」)。
页面顶部另有一行运行状态(端口 / TLS / 上次错误),由插件自己的只读路由 GET /lan-gateway/config 提供;这个路由的 POST 写入口为兼容旧版客户端保留,新版卡片不再使用它。下表既是卡片字段,也是配置键:
键 · 默认值 · 说明
enabled · false · 是否在启动时监听网络端口
gatewayPort · 3081 · 网关监听端口(未指定地址 / 双栈)
dshTargetPort · 跟随 ctx.webServer.port · 转发到的 dsh loopback 端口
lanCidrs · RFC1918 + link-local(见下) · 视为 LAN 的网段,仅在 lanPasswordless 开启时用作豁免匹配集
lanPasswordless · false · LAN/loopback 来源跳过网关登录页(上游会话中继仍把关)
cookieMaxAgeDays · 7 · 会话 cookie 有效期(天)
cookieName · dsh_gw_auth · 会话 cookie 名,不进卡片
tlsEnabled · false · 是否以 HTTPS 提供服务
tlsMode · self-signed · self-signed 自动生成 / custom 用自己的证书
tlsSelfSignedHosts · localhost · 自签名证书的 SAN(逗号分隔的域名 / IP)。仅影响下次换发,见下「证书有效期」
tlsCertPath · — · custom 模式:PEM 证书(或证书链)绝对路径
tlsKeyPath · — · custom 模式:PEM 私钥绝对路径
tlsCertMaxAgeDays · 825 · 自签名证书有效期(天),见下「证书有效期」
allowInsecurePlaintext · false · 允许明文 HTTP 监听(见下「入口加密」)
trustedTerminator · — · 声明一个受信 TLS 终止代理标识,视为加密入口(如 nginx)。注意登录限流的键,见下「登录限流」
secureCookies · 自动 · 会话 cookie 的 Secure 属性显式开关,默认按 tlsEnabled 或 trustedTerminator 推断(见下)
默认 lanCidrs:10.0.0.0/8、172.16.0.0/12、192.168.0.0/16、169.254.0.0/16。IPv6 的 fe80::/10(link-local)与 127.0.0.0/8、::1 归为 LAN/loopback。
配置里残留 authRequired: false(v0.4 及更早的写法)会被启停守卫拒绝并提示迁移,不会静默降级成免密。
登录密码
卡片顶部就是「登录密码」栏:一个「已设置 / 未设置」状态,两个密码框(新密码、再次输入),点「修改密码」直接覆盖原密码。
- 不回显旧密码。 界面只报告密码是否存在;卡片读不到旧密码。
state.json里只有 scrypt 哈希与盐,/lan-gateway/password也从不把哈希、盐或长度返回给浏览器。 - 不需要旧密码。 该路由与配置路由共用同一道围栏:只接受本机 loopback 的同源请求(Host 必须是回环、跨站请求拒绝、带
Origin时必须与 Host 匹配;不带Origin的写操作放行——桌面版的dsh-app://app桥会剥掉这个头,dsh 自己的路由规则也不要求它)。经网关访问时,只有宿主机本机浏览器(回环来源 + 回环地址)能被放行到这道围栏,远程浏览器仍是一律 403。能通过这两道门的本地用户本来就能读~/.dsh。 - 改完即生效。 写盘后递增会话代次:旧密码立即失效,所有已登录会话与已建立的 WebSocket 全部作废,各来源需要重新登录。
- 只设置,不清空。 清空密码会按设计停掉监听器(没有密码不允许监听),卡片不做这件事;要清空请用
lan_gateway set-password
…(truncated)
Rendered from the README published on npm. Formatted only, not edited.
Versions
Published on npm::17,最后更新 2026-11-05