DeepSeek Harness Hub
← 返回列表

Linjiangxian0203/dsh-remote-tunnel

DeepSeek Harnessspec-screened在 GitHub 查看 ↗
✓ 可直接安装

Remote Host Tunnel Manager:把「本地浏览器 → 远程 Linux 服务器上的 dsh…

自动检查通过:npm 包已发布且 engines 声明满足基线(声明 Node >=22.19);该结论来自程序自动检查,未经人工实机验证。 · 最近上游提交 2026/9/14 · 已提供中文文档

dsh 的远程主机隧道管理器:远程端口分配 + 注册表 + 弹性 SSH 隧道

综合分
33.2
GitHub 分
33.2
用户评分
★ Stars
5
周下载量
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add dsh-remote-tunnel
npm 包 dsh-remote-tunnel 已校验归属本仓库,走 npm 安装最省事
数据截至 2026/9/18(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
安装兼容性检查✓ 自动检查通过

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

npm 包dsh-remote-tunnel @ 0.1.12
Node 引擎要求 >=22.19 · 基线 Node 22.19 满足
dsh CLI 依赖未声明 dsh 版本约束
入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后验证 2026/9/18 16:59:33

依赖的 DSH / Cordis 模块
@deepseek-ai/dsh-cmdline
用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动

README

dsh-remote-tunnel

Awesome DSH Plugin

Remote Host Tunnel Manager:把「本地浏览器 → 远程 Linux 服务器上的 dsh web」这条链路自动化——远程端口分配与登记、systemd 守护、SSH 隧道保活、本地 URL 输出、全生命周期管理,并面向多人共用同一台服务器的场景。

- 会话与文件都在服务器上(远程 dsh web 的工作区 = 服务器目录),本地只开一条隧道
- 每个使用者自动分到独立的远程端口,分配前在服务器上双重检查(真实占用 + 登记表),并发也安全
- 每次分配都在服务器上的登记表留档(/etc/dsh-ports.tsv 或按权限自动降级),可随时 audit 对照审查
- 隧道断线自动重连(进程退出后按退避重新拉起),心跳定期刷新登记表
- 本地端口被占自动顺延,并报告占用者进程

如果你只是使用者(不开发)

1. 安装(npm 发布版)
dsh plugin --profile remote add dsh-remote-tunnel
想在 web UI 里也看到它(「设置 → 插件」)并用 /remote 斜杠命令?
再装进 web profile,并重启 dsh web:
dsh plugin --profile web add dsh-remote-tunnel

⚠️ 多人共用同一台服务器?先做一次性注册(需要 root,见下面「多用户共享服务器」一节):
不注册也能用,但会退化成每人一份私有登记表 —— audit 只看得到自己占的端口

2. 确认你的服务器能被识别(~/.ssh/config 里的 Host 别名自动发现)
dsh --profile remote hosts
没有?手动定义一台:
dsh --profile remote hosts add lab --host 192.0.2.10 --user alice --workspace /home/alice/project

3. 第一次先体检,缺什么它逐项告诉你(密钥/Node/dsh/登记表/systemd)
dsh --profile remote check lab

3.5 体检说 Node/dsh 缺失?按你登录的账号一键补齐(幂等;师兄师姐各自跑一次)
dsh --profile remote bootstrap lab
--upgrade 则强制把远程 dsh 更新到最新版

4. 起隧道,浏览器自动打开服务器上的 dsh web
dsh --profile remote up lab --open

日常:status 看状态 / down 收尾 / logs 看远端日志 / audit 审查端口登记
dsh --profile remote down lab

远程服务器需要:Node ≥ 22.19、dsh、systemd、免密钥 ssh 登录。每个账号(包括实验室里其他师兄师姐各自的账号)在自己电脑上跑一次初始化即可,幂等:
dsh --profile remote bootstrap lab(同一脚本亦可手动:ssh  'sh -s'  remote CLI profile 是插件的主界面。装进 web profile 才会让插件出现在「设置 → 插件」里、并启用聊天中的 /remote 斜杠命令——装完记得重启一次 dsh web。

要求

- 本地:Windows/macOS/Linux,自带 OpenSSH 客户端(Windows 10+ 已内置),Node ≥ 22.19
- 远程:Linux,Node ≥ 22.19 + dsh(用 dsh --profile remote bootstrap  或 scripts/bootstrap-remote.sh 安装,每个账号各自装一次),systemd(用户级即可,无需 root)
- 推荐:远程已配置 SSH 免密钥登录(ssh  直接能进,不弹密码)

安装

1. 安装到专用 CLI profile(推荐;首次会自动初始化 remote profile)
cd           # 或 npm 包名 dsh-remote-tunnel
dsh plugin --profile remote add .

2. 装到 web profile,让插件在 web UI 的「设置 → 插件」里可见、
并启用聊天里的 /remote 斜杠命令;装完重启 dsh web
dsh plugin --profile web add .

快速上手

看看有哪些主机(~/.ssh/config 里的 Host 别名会被自动发现)
dsh --profile remote hosts

也可以手动定义一台主机(不含 ~/.ssh/config 时)
dsh --profile remote hosts add lab --host 192.0.2.10 --user alice --workspace /home/alice/project

就绪诊断:密钥/Node/dsh/登记表/systemd 逐项检查
dsh --profile remote check lab

一键:分配远程端口 → 登记 → 写 systemd 单元并启动远程 dsh web → 本地起隧道
dsh --profile remote up lab --open

输出示例:
allocated remote port 3081 (range 3080-3119, registered for alice)
✓ tunnel up — http://127.0.0.1:3083 (remote lab:3081)
stop: dsh --profile remote down lab   (or Ctrl+C)

查询/停止/审查
dsh --profile remote status lab
dsh --profile remote logs lab            # 远程 dsh web 日志(journalctl)
dsh --profile remote audit lab           # 登记表 vs 真实占用
dsh --profile remote down lab            # 停隧道 + 登记表 released + 停服务 + 核实端口已释放

打开本地 URL 后,登录到的是服务器上的 dsh web:能对话、能读写服务器文件。API key 在远程 web 的「设置 → 模型」里配置(写入服务器 ~/.dsh/.credentials.yaml,本插件与隧道不触碰凭据)。

命令一览

hosts / hosts add  --host H [--port 22] [--user U] [--workspace DIR] / hosts rm
check                      就绪诊断(可作 CI 探针,非零退出码 = 有问题)
bootstrap  [--upgrade]     按登录账号补齐远程环境:Node/dsh(~/.npm-global)/~/.dsh/linger(幂等)
provision  [--port N]      只做远程侧:分配端口 + systemd 单元 + 启动 + 登记(不起隧道)
up  [--port N] [--local-port N] [--open] [--heartbeat 秒]
down [host] [--keep-service]     停隧道 + released + 停单元 + 核实端口释放
status [host] [--json]
list
logs  [--lines N] [--follow] [--local]
audit  [--json] [--release ] [--clean-stale]
open [host]
config show / config path

工作原理

1. 远程端口分配(原子):一条远程脚本在 flock 锁内完成——读登记表的 in-use 集合 + 对区间内每个端口做真实 bind 探测 → 取第一个「两者都空闲」的端口 → 追加 TSV 行 → 回显端口。多账号并发分配互不冲突。
2. 远程守护:写入 systemd 单元并 enable --now。有密码 sudo 时用系统级单元(/etc/systemd/system/dsh-web-.service,与任务书模板一致);没有 sudo 时自动改用用户级单元(~/.config/systemd/user/dsh-web.service)+ loginctl enable-linger,完全不需要 root。服务器重启自动拉起,崩溃自动重启。
3. TOCTOU 兜底:若 dsh 启动时端口被抢(EADDRINUSE 出现在单元日志),自动把该端口加入排除集,顺延下一个空闲端口重试(默认最多 5 轮)。
4. 本地隧道:ssh -N -L 127.0.0.1::127.0.0.1: ,本地端口先检查占用(被占自动顺延,并用 netstat+tasklist 报出占用者);ssh 进程退出后按退避序列(1s→2s→4s→8s→15s→30s 封顶)自动重连,永不断线(可配 maxAttempts)。隧道明确不传 ClearAllForwardings(Windows OpenSSH 会把它连同命令行 -L 一起清掉);exec 会话仍会清掉 config 里的转发。
5. 心跳:隧道存活期间每 heartbeatSeconds(默认 120 秒)在锁内原位刷新登记表 last_heartbeat。
6. 释放:down(或 up 的 Ctrl+C)按序:停隧道 → 删除本地状态 → 登记表 released → 停远端单元并 disable(禁用,避免服务器重启后自己回来占住已释放的端口)→ 核实端口真的释放。up/provision 会重新 enable;--keep-service 则完全不动远端单元。另一个进程里的 up 监督器检测到状态文件被删除后自动停止重连,不会「诈尸」。硬关终端(不按 Ctrl+C)则远端服务照跑、登记表仍是 in-use——这是真实占用,不是泄漏:下次 up 会自动清理残留的本地状态并复用同一个已登记端口,不会越攒越多。

配置

$DSH_HOME/remote-tunnel/config.yaml(dsh --profile remote config path 查看路径):

hosts:
lab:                      # 手动定义的主机(与 ~/.ssh/config 的别名合并,二者同名时这里优先)
host: 192.0.2.10
port: 22
user: alice
workspace: /home/alice/project
remotePortRange: [3080, 3119]   # 可选,按主机覆盖
defaults:
remotePortRange: [3080, 3119]     # 远程 dsh 端口区间(先查占用再分配)
localPortRange: [3081, 3140]      # 本地隧道端口区间
registry:
path: /etc/dsh-ports.tsv
lockPath: /etc/dsh-ports.lock
sudo: auto                      # auto | always | never
fallbackPath: .dsh-ports.tsv    # 共享登记表不可写时,降级到远程家目录(相对路径)
unit:
prefix: dsh-web-
restartSec: 5
type: auto                      # auto | system | user
heartbeatSeconds: 120             # 0 = 关闭心跳
remoteWaitSeconds: 60             # 等远程端口就绪
localWaitSeconds: 15              # 等本地 URL 可访问
reconnect:
delaysMs: [1000, 2000, 4000, 8000, 15000, 30000]
maxAttempts: 0                  # 0 = 永不放弃
allocateRetries: 5
ssh:
connectTimeout: 0               # 0 = 不传 -o ConnectTimeout(见排错表)
extraArgs: []

多用户共享服务器(实验室场景:先做这一步)

多人用同一台服务器时,建议第一次先用 root 做一次性注册——否则插件会自动降级为"每人一份私有登记表",
端口分配只能靠真实占用探测避让(仍然不会连错、不会永久撞车,但 audit 看不到别人占了哪些端口)。

注册一次(需要 root,之后永不再做)——建共享登记表 + 共享组:

sudo groupadd -f dshports
sudo install -m 0664 -o root -g dshports /dev/null /etc/dsh-ports.tsv
sudo install -m 0664 -o root -g dshports /dev/null /etc/dsh-ports.tsv.lock
sudo usermod -aG dshports   ...    # 需要用到插件的每个账号

两个文件都必须提前建好:它们位于仅 root 可写的目录里,成员自己无法创建锁文件,而所有登记操作都要先拿这把锁。
只有这两个文件带组写权限(0664),所在目录保持仅 root 即可——更新登记表时插件用用户级 mktemp 中转、原地改写,
既不触碰目录,也不改变文件的属主/组。

每个成员:① 重新 SSH 登录一次让组生效;② 首次准备环境 dsh --profile remote bootstrap ;
③ dsh --profile remote check  应显示 registry: /etc/dsh-ports.tsv (shared-direct)——无需改任何配置,
插件会自动从私有登记表切到共享表。

之后每个人 up 的分配都在服务器上被 flock 串行化并写入同一张表:分到的远程端口必定互不相同,
audit 能直接看出"谁占了哪个端口、有无 stale/冲突"。无主行定期清理:dsh --profile remote audit  --clean-stale。

| 服务器环境 | 登记表 | 服务守护 |
|---|---|---|
| 管理员按上面建了 dshports 组(推荐) | /etc/dsh-ports.tsv(组 0664,免 sudo) | 用户级单元 + linger |
| 成员都有 passwordless sudo | /etc/dsh-ports.tsv(sudo 写入,0644) | 系统级单元,一人一个端口 |
| 什么都没配 | 自动降级 ~/.dsh-ports.tsv(只含本人记录;check 会提示找管理员) | 用户级单元 + linger |

共享登记表全员可读(0644/0664),里面只有端口、账号、工作区、来源、时间戳和状态——不含任何密码、密钥或 token;
写入由 flock 串行化,非本组成员无法篡改。

每个账号各自准备好自己的环境(一台服务器 N 个用户 = 各自跑一次,幂等):

dsh --profile remote bootstrap      # 在自己电脑上,以自己账号 ssh 登录后执行

这一步把 Node/dsh(装进该账号自己的 ~/.npm-global)/~/.dsh/linger 全部补齐——它不碰别的账号的任何东西,会话历史也按账号彼此独立。

两个用户各自 up → 自动分到不同远程端口;audit 能看出谁占哪个端口、有无 stale/冲突。

远程账号初始化(bootstrap,按登录账号)

dsh --profile remote bootstrap  为 ssh 别名登录的那个账号补齐环境:Node ≥ 22.19(缺失时尽量装)、dsh(装进该账号 ~/.npm-global)、~/.dsh、systemd linger、npm-global 的 PATH 条目——幂等,新账号跑一次即可。--upgrade 则会强制把 dsh 更新到最新版。

dsh --profile remote bootstrap lab              # 准备好当前账号
dsh --profile remote bootstrap lab --upgrade    # 更新远程 dsh 到最新版

同一脚本也随包提供,可手动执行(和插件行为完全一致):

ssh  'sh -s'  按当前账号补齐(幂等,--upgrade 可更新);已装但 ssh 通道 PATH 看不到时,插件也会自动探测 ~/.npm-global/bin/dsh。 |
| Error: listen EADDRINUSE ... 127.0.0.1:3080 | 有人(或你上一个实例)占了该端口。本插件分配前双重检查,up 时若仍发生(TOCTOU)会自动顺延;手工起 dsh 才会看到这个报错。 |
| Could not resolve hostname  | 别名不在 ~/.ssh/config 里,且没在插件配置里定义。hosts add 或写入 ssh config 后重试。 |
| Connection refused / remote port forwarding failed | 远端 dsh web 没起或端口不对。check  看「web port listening」;logs  看远端日志;ss -tln \| grep  在服务器上核实。 |
| channel_setup_fwd_listener_tcpip: cannot listen to port | 本地端口已被占(常见:两个 dsh web 实例)。本插件会自动顺延,并输出占用者进程名;也可 --local-port 手动指定。 |
| Permission denied (publickey) / sudo: a password is required | 密钥没配好 / 没有 NOPASSWD sudo。前者 ssh-copy-id;后者见上表,无 sudo 也能用(用户级单元 + 兜底登记表)。 |
| Could not create directory '/home/xxx/.ssh' + host key 提示 | 首次连接需接受主机指纹,插件默认 accept-new(TOFU),已在自动处理。 |
| 断网后隧道没恢复 | 默认无限重连,status 看 ssh pid 是否 alive;logs  --local 看重连日志。若设了 reconnect.maxAttempts,达到上限会停止。 |
| 隧道进程一直活着,但本地 URL 始终 not reachable(端口不通) | Windows OpenSSH 8.1 会把 -o ClearAllForwardings=yes 连同命令行自己的 -L 一起清掉,导致隧道只连接、不转发。已于 0.1.1 修复:隧道不再传该选项(exec 会话仍保留)。 |
| 打开隧道 URL 只显示 dsh web authentication required; reopen the URL printed by dsh web. | dsh web ≥ 0.1.2-rc 用启动时打印的一次性 token URL 鉴权。up 现在会打印改写成本地端口的带 token 地址(auth: 行)。若已过期(服务重启过),把 logs  里的 dsh web: http://…?token=… 整行复制到浏览器地址栏。 |
| 登记表读不到(/etc/dsh-ports.tsv missing) | 首次分配时自动创建(需写入权限);无权限时自动降级到 ~/.dsh-ports.tsv,check 会给出管理员初始化命令。 |
| 每条 ssh 命令都慢 ~N 秒 | 部分服务器上给 ssh 传 ConnectTimeout 会让每条连接都等满超时(即使秒连)。默认已不传该参数(ssh.connectTimeout: 0);需要时再显式打开。 |
| Bad owner or permissions on .../.ssh/config(所有远程操作全挂) | 你的 ~/.ssh/config 里被别的工具(如 AtomGit DevEnv、conda 环境)注入了 Include,而那个被包含的文件权限过宽(带 Everyone:(F)),OpenSSH 直接拒绝加载整份配置。修复:icacls "" /inheritance:r /grant:r "$env:USERDOMAIN\$env:USERNAME:F" /grant:r "NT AUTHORITY\SYSTEM:F"(目录同样处理)。另一种成因是 HOME 被工具改指到别处,使 ssh 读了另一个目录下的 config——echo $env:HOME 确认。 |
| audit 显示某些 in-use 行是 STALE,端口总被"占用" | 那是会话被杀/硬关终端后没来得及 down 留下的历史行(分配时会当作占用,避免撞车)。清理:dsh --profile remote audit  --clean-stale。 |

开发与测试
bash
npm install             # 插件自身依赖(package-lock.json 已入库,构建可复现)
npm test                # 单元测试 + 假 ssh shim 集成测试(无需真实服务器)

集成测试用一个仿真的 ssh(把远程命令解释到临时「服务器」上,隧道真实转发 TCP),覆盖:分配/登记/释放、并发多人分配、TOCTOU 顺延、本地端口冲突顺延、断线自动重连、跨进程 down 取消、audit stale/orphan/clean。

安全说明

- 隧道与远程 dsh 一律只绑 127.0.0.1(dsh 本身禁止 --host 0.0.0.0)
- 插件不保存、不传输任何密码/密钥/API key;SSH 全走现有密钥(BatchMode,拒绝密码提示挂起)
- 登记表不记录任何敏感信息(见 docs/registry-format.md · English)
- 远程脚本仅在 flock 锁内追加/改写登记表与 systemd 单元,不执行其他写入

非目标

- 不实现 SSH/SFTP/远程挂载:方案本质是「在服务器上跑 dsh」,隧道只把 HTTP 引回本地
- 不做新 TUI:CLI 子命令 + web 的 /remote 斜杠命令

上游仓库有新提交时邮件通知你(每天最多一封,无更新不打扰),随时一键退订。

💬 加入 DPharness 群聊

插件用法、部署报错、新插件第一时间同步——群里问,比一个人翻文档快。

点击加入 QQ 群
DPharness 群聊二维码,手机 QQ 扫码进群
扫码进群