dsh-remote-access:通过 Tailscale 等私有组网远程访问 DSH 桌面端

前言

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。

核心功能

  1. 一个开关启用远程访问。面板显示 listener 状态、可用链接、绑定地址。
  2. 默认使用检测到的 100.64.0.0/10 mesh 地址(Tailscale、ZeroTier、NetBird 共用这个段),优先于 LAN 地址,避免在咖啡馆 Wi-Fi 上把 agent 暴露给局域网。
  3. 默认不设 key,网络就是访问边界:能到达该端口的 mesh 设备即可获得访问权限。
  4. 可选的 Browser access key:开启后每个新浏览器输入一次 key,浏览器只持有 HMAC cookie;替换 key 会让所有现有 cookie 失效。
  5. Tailscale 的 MagicDNS 名称会被优先用于链接(形如 http://host.tailnet.ts.net:3080/),地址变化后仍可用。CLI 不可用时也能用裸 IP 链接。
  6. 开启 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,以实际构建输出为准。

构建完成后:

  1. 在 Settings → Plugins 里安装打包好的 tarball,然后重启应用。运行中的 profile 无法导入新捆绑,必须重启。
  2. 打开 Settings → Remote Access。
  3. 点 Enable mesh access,面板会绑定检测到的 mesh 地址并显示链接。
  4. 在同一 mesh 的某台设备上打开该链接。默认不会要求 key:私有网络本身就是访问边界,你在 Tailscale / ZeroTier / NetBird 里管理的节点成员关系就是授权。
  5. 可选:网络是共享的就打开 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 隧道的场景,这个插件相当于给了你一地址一开关的入口。

几个必须知道的限制:

  1. harness 必须处于运行状态。网关活在 harness 进程里,机器睡眠就切断远程访问。
  2. 一个进程只代理一个 harness 实例(即本 profile)。
  3. 没有 TLS 终结,也没有证书管理。安全性依赖 WireGuard 层和你的 tailnet ACL。
  4. mesh 地址不受局域网变化影响,但 Tailscale 重新登录可能换地址,面板会在一分钟内重新绑定。
  5. 这个插件以当前 dsh 进程的权限运行,并且运行前应当读一遍源码、核对许可证(MIT)后再决定是否安装。
  6. 撤销访问要么从网络 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
羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜