前言¶
DSH 的桌面端默认把 Web 监听器绑在 loopback:dsh web 的 --host 只接受具体地址,0.0.0.0 会在启动时被明确拒绝;桌面应用更是直接以 --host 127.0.0.1 --port 0 拉起 harness。所以在办公室之外的设备上打开这个界面,原生没有留口子。
icrefin 维护的 dsh-remote-access 插件给出的答案是放一个网关:不尝试改变现有监听器的绑定方式,而是自己在组网地址上加一层反向代理,把请求转发给本机 loopback 上的 harness。安装后面板位于 Settings → Remote Access,默认关闭。
这个插件解决什么问题¶
一句话定位:在 Tailscale、ZeroTier、NetBird 这类私有 mesh 网络上,从手机、平板或另一台电脑访问本机 DeepSeek Harness 的完整客户端界面,而不是一个阉割过的远程控制页。
工作方式是这样的:
phone / laptop this machine
┌──────────────┐ WireGuard ┌─────────────────────────────┐
│ browser │──────────────▶│ 100.x.y.z:3080 │
│ (real DSH UI)│ │ └─ key gate → replay ──┐ │
└──────────────┘ │ ▼ │
│ 127.0.0.1:<random> harness│
│ (unchanged, loopback only) │
└─────────────────────────────┘
浏览器加载的和本机窗口加载的是同一个页面,会话、prompt、流式输出、终端、设置天然完整。网关每个请求只做几件事:检查自己的 cookie、附加它签发的 harness cookie、把 Host 改写为 loopback、去掉 Origin/Referer/Sec-Fetch-*,然后把响应流回去。WebSocket 升级按裸 socket 隧道透传。
由于 mesh 传输本身是 WireGuard 加密的,网关在 3080 端口上跑普通 HTTP,不做 TLS 终结,也明确不假装能终结 TLS。
核心功能¶
- 一个开关启用远程访问。面板显示 listener 状态、可用链接、绑定地址。
- 默认使用检测到的
100.64.0.0/10mesh 地址(Tailscale、ZeroTier、NetBird 共用这个段),优先于 LAN 地址,避免在咖啡馆 Wi-Fi 上把 agent 暴露给局域网。 - 默认不设 key,网络就是访问边界:能到达该端口的 mesh 设备即可获得访问权限。
- 可选的 Browser access key:开启后每个新浏览器输入一次 key,浏览器只持有 HMAC cookie;替换 key 会让所有现有 cookie 失效。
- Tailscale 的 MagicDNS 名称会被优先用于链接(形如
http://host.tailnet.ts.net:3080/),地址变化后仍可用。CLI 不可用时也能用裸 IP 链接。 - 开启 key 时有登录限速:每个客户端每 15 分钟最多 8 次错误尝试。
插件提供的接口面(全部来自 README):
| 接口 | 作用 |
|---|---|
GET /api/dsh-remote-access/status |
listener 状态、检测到的接口、绑定错误 |
POST /api/dsh-remote-access/config |
在线修改设置,通过 settings service 持久化 |
GET /api/dsh-remote-access/key |
返回链接(key 开启时链接里附带 key) |
POST /api/dsh-remote-access/regenerate |
替换 key 并使所有 cookie 失效 |
http://<mesh-address>:3080/ |
可选 key 门禁,随后在 loopback 上重放 harness |
配置字段:
| 字段 | 默认值 | 含义 |
|---|---|---|
enabled |
false |
listener 是否运行 |
port |
3080 |
mesh 地址上的 TCP 端口 |
bindHost |
auto |
auto(检测 mesh 接口)、all(0.0.0.0)或 IPv4 地址 |
requireKey |
false |
是否要求浏览器先通过 key |
面板通过 harness 的 settings service 写入,配置落在 profile 的 cordis.patch.yml,重启后仍在。如果某次写入无法持久化,界面会显示 Applied, but not saved。
插件以捆绑(bundle)方式安装,附带 cordis.patch.yml,需要 dsh 0.2.1-rc.5,Node >=22.17.0,许可证 MIT。
安装与启用¶
README 给出的安装方式是本地构建后从设置界面安装 tarball,不是命令行直连仓库:
pnpm install
pnpm check # typecheck both halves, build, run 86 tests
pnpm run pack # -> dist/dsh-remote-access-0.1.2.tgz
scripts/install.sh
注意 pnpm run pack 产物名里的版本号是仓库示例,当前 package.json 版本为 0.1.3,以实际构建输出为准。
构建完成后:
- 在 Settings → Plugins 里安装打包好的 tarball,然后重启应用。运行中的 profile 无法导入新捆绑,必须重启。
- 打开 Settings → Remote Access。
- 点 Enable mesh access,面板会绑定检测到的 mesh 地址并显示链接。
- 在同一 mesh 的某台设备上打开该链接。默认不会要求 key:私有网络本身就是访问边界,你在 Tailscale / ZeroTier / NetBird 里管理的节点成员关系就是授权。
- 可选:网络是共享的就打开 Browser access key,之后每个新浏览器输入一次 key;Replace key 可吊销全部。
配合 Tailscale 时,建议在 tailnet ACL 里限制端口。README 给出的例子:
{ "action": "accept", "src": ["autogroup:member"], "dst": ["tag:my-mac:3080"] }
并特别强调:不要用 Tailscale Funnel。Funnel 会把端口暴露到公网,这个插件的前提是私有网络。
适用场景与注意¶
适合谁:已经在用 Tailscale / ZeroTier / NetBird,想在 mesh 里用另一台设备临时使用本机 DSH 界面的人。不想把端口暴露到公网,也不打算自己搭 SSH 隧道的场景,这个插件相当于给了你一地址一开关的入口。
几个必须知道的限制:
- harness 必须处于运行状态。网关活在 harness 进程里,机器睡眠就切断远程访问。
- 一个进程只代理一个 harness 实例(即本 profile)。
- 没有 TLS 终结,也没有证书管理。安全性依赖 WireGuard 层和你的 tailnet ACL。
- mesh 地址不受局域网变化影响,但 Tailscale 重新登录可能换地址,面板会在一分钟内重新绑定。
- 这个插件以当前 dsh 进程的权限运行,并且运行前应当读一遍源码、核对许可证(MIT)后再决定是否安装。
- 撤销访问要么从网络 ACL 移除设备,要么在开启 key 的情况下替换 key。没有逐设备的 key 列表。
结尾¶
dsh-remote-access 的价值在于它没有试图改写 harness 的监听策略,而是补上了「私有网络内可达的完整客户端」这一层:一个网关、一个开关、一条链接,默认关闭、默认只绑 mesh 地址。如果你的访问需求限定在自己管理的 mesh 内,这是目前比较干净的方案。
- 目录页:https://www.skillhub.cn/plugins/icrefin/dsh-remote-access
- GitHub:https://github.com/icrefin/dsh-remote-access