Back to home@SunNull

dsh-relay

Cloud relay for DeepSeek Harness: expose your home dsh instance to any device with full real-time sync (out-of-tree plugin + wire-trunk architecture)

Stars
0
Language
JavaScript
Created
Aug 16, 2026
Updated
Aug 24, 2026
GitHub repo

Introduction

dsh-relay

English | 中文

把家里运行的 DeepSeek Harness(dsh)完整映射到公网 —— 在任何设备、任何地点,通过一个网址获得与你家中电脑完全一致的 dsh 体验:会话实时同步、流式输出、工具卡片、审批弹窗、工作区浏览,一个不少。

手机 / 外网电脑 ──HTTPS──→ 云端中继(dsh-relay-cloud,一台 VPS)
                              │  出站长连接干线(家端主动拨出)
                              ▼
                        家中 dsh(保持 127.0.0.1 回环绑定,零端口暴露)
                        └─ dsh-relay-host 插件:进程内"隐形浏览器",
                           以回环身份复放全部请求

它是如何工作的(Wire-Trunk 架构)

  • 家端是一个树外插件(~200 行,零构建):它作为"dsh 进程里的隐形浏览器",对本机 127.0.0.1:3080 发起与真实浏览器完全相同的协议连接(POST /api/* + 两条下行 WebSocket),并把它们原封不动复用到云端。
  • 云端是纯转发面:对远端浏览器呈现与 dsh 原版逐字节一致的 wire;静态资源由家端实时上报、云端缓存——前端与宿主永远同版本,不存在协议漂移。
  • 不修改 dsh 仓库任何一行代码:插件挂在 ~/.dsh/profiles/web/ 用户补丁层,git pull、自动更新、随时卸载互不干扰。
  • 安全性:dsh 本身无认证层且特权方法钉死回环——本方案恰好让请求以回环身份进入,同时把认证(配对码 → 长期 Cookie)补在云端入口;家端零入站端口,天然穿 NAT。

完整部署教程

三个角色:云端(一台公网服务器)、家端(运行 dsh 的电脑)、远端(手机/任何浏览器)。按顺序做完约 15 分钟。

前置条件

角色要求
云端公网 IP 的 Linux 服务器(1 核 1G 起步即可),能 SSH 登录,开放一个 TCP 端口(下文用 8443)
家端已能运行 dsh web(默认 127.0.0.1:3080),Node ≥ 22
远端任何现代浏览器

第 1 步:准备凭据(家端电脑上执行)

生成两个强随机值,后面所有步骤都用它们:

# 干线令牌(家端 ↔ 云端的身份凭证,32 位)
node -e "console.log(require('crypto').randomBytes(24).toString('hex'))"
# 记作 <TOKEN>,例如 9f86d081884c7d65...

# 配对码(远端浏览器首次访问输入,8 位)
node -e "console.log(require('crypto').randomBytes(4).toString('hex'))"
# 记作 <CODE>,例如 a1b2c3d4

⚠️ 这两个值就是整套系统的钥匙,生成后妥善保存,不要提交进任何仓库。

第 2 步:部署云端

SSH 登录你的服务器:

ssh root@<你的服务器IP>

2.1 安装 Node 22(已装可跳过;node -v 检查):

ARCH=$(uname -m); case "$ARCH" in x86_64) NARCH=x64;; aarch64) NARCH=arm64;; esac
curl -fsSL https://cdn.npmmirror.com/binaries/node/v22.14.0/node-v22.14.0-linux-$NARCH.tar.xz -o /tmp/node.tar.xz
tar -xJf /tmp/node.tar.xz -C /opt
ln -sfn /opt/node-v22.14.0-linux-$NARCH /opt/node
ln -sf /opt/node/bin/node /usr/local/bin/node
ln -sf /opt/node/bin/npm /usr/local/bin/npm
node -v   # 应显示 v22.14.0

2.2 获取代码并安装依赖

git clone https://github.com/SunNull/dsh-relay.git /opt/dsh-relay
cd /opt/dsh-relay/cloud
npm install --registry=https://registry.npmmirror.com

2.3 创建 systemd 常驻服务(把 <TOKEN>/<CODE> 换成第 1 步生成的值):

cat > /etc/systemd/system/dsh-relay.service <<EOF
[Unit]
Description=dsh-relay cloud
After=network-online.target

[Service]
Environment=DSH_RELAY_BIND=0.0.0.0
Environment=DSH_RELAY_PORT=8443
Environment=DSH_RELAY_TOKEN=<TOKEN>
Environment=DSH_RELAY_PAIRING_CODE=<CODE>
WorkingDirectory=/opt/dsh-relay/cloud
ExecStart=/usr/local/bin/node server.mjs
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now dsh-relay
systemctl status dsh-relay        # 应为 active (running)
curl -s http://127.0.0.1:8443/healthz   # 应返回 {"ok":true,...,"trunkReady":false}

trunkReady:false 是正常的——家端还没连。

2.4 云防火墙/安全组放行 8443(TCP 入方向,源 0.0.0.0/0):

  • 阿里云/腾讯云:控制台 → 实例 → 安全组/防火墙 → 添加规则 TCP 8443
  • 服务器自身若开了 ufw:ufw allow 8443/tcp

家端电脑浏览器打开 http://<服务器IP>:8443/healthz 验证,应返回 JSON——通了。

第 3 步:安装家端插件

在家端电脑(dsh 所在机器),二选一:

方式 A:标准 bundle 安装(仓库声明 dsh.bundle,一条命令挂载):

dsh plugin --profile web add "github:SunNull/dsh-relay"

然后在 ~/.dsh/profiles/web/cordis.patch.yml 追加干线配置(bundle 层不携带凭据,用户层覆盖):

- id: dsh-relay-host
  config:
    relayUrl: ws://<你的服务器IP>:8443/trunk
    token: <TOKEN>

方式 B:安装器一条龙(克隆仓库并自动写好配置):

git clone https://github.com/SunNull/dsh-relay.git
cd dsh-relay
node install.mjs --relay-url ws://<你的服务器IP>:8443/trunk --token <TOKEN>

安装器会:

  1. 把插件复制到 ~/.dsh/profiles/web/plugins/dsh-relay-host.mjs
  2. ~/.dsh/profiles/web/cordis.patch.yml 追加托管配置块(dsh 的补丁层热生效

两种方式都需要重启一次 dsh web(模块代码需要进程加载;之后仅改配置不再需要重启)。卸载:方式 A 用 dsh plugin --profile web remove dsh-relay-host,方式 B 用 node install.mjs --uninstall

# 停掉现有 dsh web,重新启动,例如:
pnpm dsh web

验证干线已连——在服务器上执行:

curl -s http://127.0.0.1:8443/healthz
# "trunkReady":true 即成功;false 则检查插件配置与令牌是否一致

第 4 步:远端访问

手机(或任何设备)浏览器打开:

http://<你的服务器IP>:8443
  1. 首次出现配对页 → 输入 <CODE> → 点"配对"
  2. 自动进入完整 dsh 界面(与家中电脑一模一样:会话、模型、工作区全同步)
  3. 建议"添加到主屏幕",即得类原生 App 体验

多台设备重复第 4 步即可(默认上限 10 台,见环境变量)。

第 5 步(强烈推荐):远程可选工作区

dsh 默认在宿主桌面弹原生目录选择框,远程设备看不到。追加此补丁让所有人走网页内目录浏览

编辑 ~/.dsh/profiles/web/cordis.patch.yml,在末尾追加:

- id: directory-picker
  disabled: true
- insert:
    - id: directory-picker-browse-host
      name: '@deepseek-ai/dsh-host-directory-picker-browse'
    - id: directory-picker-browse-ui
      name: '@deepseek-ai/dsh-client-ui-directory-picker-browse'

保存即热生效(这是 dsh 官方为远程部署场景设计的标准换法)。之后"添加工作区"会打开网页目录浏览器,手机上可任意选择家中路径。

第 6 步(可选但强烈建议):HTTPS

明文 HTTP 有被运营商劫持/窃听风险。有一个域名即可上自动 HTTPS:

# 服务器上安装 Caddy(以官方 apt 源为例)
apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list
apt update && apt install caddy

把 DNS A 记录指向服务器 IP,然后:

cp /opt/dsh-relay/cloud/Caddyfile.template /etc/caddy/Caddyfile
# 编辑文件,把 dsh.example.com 换成你的域名
nano /etc/caddy/Caddyfile
systemctl reload caddy

之后用 https://<你的域名> 访问;家端重新指向(热生效,无需重启 dsh):

cd dsh-relay
node install.mjs --relay-url wss://<你的域名>/trunk --token <TOKEN>

日常运维

操作命令/位置
查看云端状态与审计配对后访问 http://<服务器>:8443/__relay(JSON)
健康检查curl http://<服务器>:8443/healthz(无需认证)
云端日志journalctl -u dsh-relay -f
踢掉所有已配对设备服务器:systemctl stop dsh-relay && rm /opt/dsh-relay/cloud/relay-state.json && systemctl start dsh-relay
更新云端代码cd /opt/dsh-relay && git pull && systemctl restart dsh-relay(各版本变化见 CHANGELOG
卸载家端插件家端:node install.mjs --uninstall(再删掉仓库目录即完全清除)
家端 dsh 重启后无需任何操作——插件自动重连云端(断线指数退避重试)

云端环境变量

变量默认说明
DSH_RELAY_PORT3081监听端口
DSH_RELAY_BIND127.0.0.1绑定地址;公网部署设 0.0.0.0
DSH_RELAY_TOKENdev-token家端干线令牌(与插件 config.token 一致)
DSH_RELAY_PAIRING_CODE随机生成并打印浏览器配对码;建议显式设置
DSH_RELAY_STATE./relay-state.json设备令牌 + 审计日志持久化文件
DSH_RELAY_MAX_TOKENS10最多配对设备数
DSH_RELAY_MAX_WS16并发浏览器 WebSocket 上限
DSH_RELAY_BLOCK_PRIVILEGED01 = 云端拦截设置/凭据等特权方法(更保守)
DSH_RELAY_HEARTBEAT_MS20000干线与浏览器下行连接的心跳周期(毫秒)。浏览器错过一个整周期的 pong 即判定为死连接断开(前端会自动重连并重放基线),心跳流量同时防止 NAT 空闲超时

验收测试(probe/)

部署完成后跑一遍,确保全链路健康:

# 1) 干线三要素(静态/RPC/WS 桥),在任意机器:
node probe/e2e-probe.mjs   # 先编辑脚本顶部 BASE 为你的服务器地址

# 2) 浏览器全流程(配对→UI→WS),需 pip install playwright && playwright install chromium:
DSH_RELAY_BASE=http://<服务器>:8443 DSH_RELAY_PAIRING_CODE=<CODE> python probe/browser-acceptance-m1.py

安全须知(务必阅读)

  • 配对码即钥匙:通过配对的设备 ≈ 坐在你家电脑前使用 dsh(能聊天、跑命令、看文件)。公网部署必须用强配对码 + HTTPS。
  • 特权面提醒:远程默认可访问 dsh 的设置/凭据面。保守起见可设 DSH_RELAY_BLOCK_PRIVILEGED=1(远端将无法改设置/看凭据,聊天与文件功能不受影响)。
  • 云端零业务落盘:relay-state.json 只存设备令牌与审计计数,不含任何会话内容
  • 令牌轮换:换 <TOKEN> 需同步改云端 systemd 环境 + 家端重跑 install.mjs --token

故障排查

症状原因与解法
手机打开显示"家端不在线"家端 dsh 没跑 / 插件没连上。服务器 curl localhost:8443/healthztrunkReady;false 则查家端配置与网络
配对提示"设备数已达上限"之前测试占满 10 坑。按"踢掉所有设备"清理后重新配对
忘记配对码服务器上执行 systemctl cat dsh-relay | grep PAIRING(显式设置过的);若启动时未设置,看日志 journalctl -u dsh-relay | grep "pairing code"(自动生成时打印过)
更换配对码编辑 /etc/systemd/system/dsh-relay.service 中的 DSH_RELAY_PAIRING_CODE,然后 systemctl daemon-reload && systemctl restart dsh-relay。注意:已配对的旧设备不受影响(持有长期令牌);要踢掉旧设备需按上文"踢掉所有已配对设备"清理 relay-state.json
首次打开很慢(10-20 秒)正常:云端冷缓存逐个拉取静态资源,第二遍起快
远程"添加工作区"无反应没做第 5 步补丁(原生弹窗弹在了家里屏幕上)
界面空白/一直转圈先强刷新/清缓存;再跑 probe 脚本定位是静态、RPC 还是 WS 环节

已知限制

  • HTTP 响应整包缓冲(SSE 下载流除外),超大导出需等待完整传输
  • dsh web 协议无版本协商(client/host 同船发布)——前端由家端上报天然同版本;dsh 大版本升级后建议全链路回归跑一遍 probe
  • 家端插件模块更新需重启 dsh web(补丁配置热生效,模块代码不热替换)

适用版本

基于 DeepSeek Harness 0.1.0-rc.5(2026-08)验证。dsh 处于 developer preview,wire 变化时以 probe 验收为准。

License

MIT