在 DeepSeek Harness 中通过 SSH 使用远程服务器:dsh-remote-ssh 配置与排障指南

3686 字
18 分钟
在 DeepSeek Harness 中通过 SSH 使用远程服务器:dsh-remote-ssh 配置与排障指南

在 DeepSeek Harness 中通过 SSH 使用远程服务器:dsh-remote-ssh 配置与排障指南#

如果你平时在本地使用 DeepSeek Harness,但代码、数据、Conda 环境甚至 GPU 都在远程服务器上,那么一个很自然的需求就是:

能不能让 DSH 本身继续运行在我的电脑上,但让它像操作本地项目一样操作 SSH 服务器上的项目?

dsh-remote-ssh 就是为这个场景设计的。 它和“把整个 DeepSeek Harness 安装到服务器上”并不是一回事。更有意思的是,它也不是简单地把远程目录同步一份到本机。 它可以让:

本地 Mac
├── DeepSeek Harness
├── 模型配置
├── API Provider
├── Session
├── Plugins
└── Skills
│ SSH + AHP
远程 Linux Server
├── 项目源码
├── 数据集
├── Conda / Python 环境
├── Bash
├── GPU
└── 真实文件系统

也就是说: Agent 留在本机,执行环境留在服务器。


1. 关于这个插件,以及我维护的 rc.8 Web 版本#

原项目:https://github.com/Yan-Zero/dsh-remote-ssh 我基于它维护了一个针对新版 DeepSeek Harness 的版本:https://github.com/Zhong0118/dsh-remote-ssh 上游目前的插件包版本为 0.2.4,主要基于 DeepSeek Harness 0.1.0-rc.6 的 package surface 开发。

我的版本当前位于:0.2.5,主要基于 DeepSeek Harness 0.1.0-rc.8 同时去掉了原项目中的 TUI 相关适配,专门聚焦目前我实际使用的:DSH Web

项目上游版本我的版本
插件0.2.40.2.5
DSHrc.6rc.8
Web
TUI✅ 可选❌ 移除
定位Web + TUIWeb 优先

后续我也可能继续基于这个版本做一些 Web 侧的功能和体验优化。


2. dsh-remote-ssh 到底做了什么?#

这个插件最重要的设计理念其实不是“SSH”,而是:

把远程目录变成 DSH 的一个透明 Workspace。

例如本地项目可能显示为:LOCAL > my-project 远程项目则显示成:Server > aigc_detector 当你进入本地 Workspace 时:

read
write
grep
glob
bash
background task

这些工具全部操作本机。

进入远程 Workspace 时,同样这些工具则被透明地路由到服务器。 也就是说,模型看到的仍然是:

read
grep
bash

而不是另一套:

remote_read
remote_grep
remote_bash

这是我比较喜欢这个插件的地方。 上游设计明确要求:当 Workspace 是远程的时,文件系统、搜索、Shell 和后台任务都在对应 SSH 主机执行;如果远程环境失败,也不会偷偷 fallback 到本机。


3. 它不是“同步工具”#

这一点特别重要。 假设服务器项目是:

/home/user/projects/aigc_detector

把它加入 DSH 后,并不意味着:

Server
↓ rsync
Mac
本地复制一整份项目

真实情况更接近:

DSH Workspace
├─ 身份:Server > aigc_detector
└─ 实际文件仍然位于
/home/user/projects/aigc_detector

因此服务器上一个几十 GB 的项目,不会因为你把它加入 DSH 就自动下载几十 GB 到本机。 这也让本地和服务器之间保持了非常清晰的边界。


4. Remote Workspace 和 Backend 是两回事#

这是使用这个插件时最容易混淆的地方。

Remote Workspace#

这是我日常更推荐的一种模式。 架构是:

Mac
├── DSH
├── Agent
├── Session
├── Model / API
├── Plugins
├── Skills
└──── SSH + AHP ────► Server
├── Files
├── Bash
├── Search
├── Python
├── Conda
└── GPU

简单说:

脑子在本机,手在服务器。

服务器只是 DSH 的远程执行环境。 这也是本文主要讲的模式。


Full Backend#

插件还有另外一种模式:

在 Web 中打开 Backend

这个模式完全不同。 此时会变成:

Mac Browser
│ SSH tunnel
Remote Server
├── dsh-host
├── Agent
├── Session
├── Tools
├── Workspace
└── Harness Backend

也就是说:

整个 Harness 后端都跑到了服务器上。

插件会将匹配的 dsh-host runtime 安装在用户目录:

~/.dsh-host

不需要 root,也不会通过 apt 去修改服务器系统。 完整 Backend 模式不依赖 VS Code Server 或 AHP;首次安装还会需要 curlsha256sum、支持 xz 的 tar 以及访问 Node/npm 的网络。 因此二者可以这样理解:

Remote WorkspaceFull Backend
DSH 本体本机服务器
Agent本机服务器
Session本机服务器
Skills / Plugins本机服务器环境
项目文件服务器服务器
Bash服务器服务器
GPU服务器服务器
VS Code Server / AHP需要不需要
适合日常远程开发完整远程 Harness
如果你的需求只是:

我本地已经把 DSH、模型、插件、Skill 都配置好了,只想操作服务器项目。

那么通常没必要开 Backend。直接使用 Remote Workspace 更简单。


5. 权限模型:DSH 到底能访问服务器什么?#

这里也需要特别注意。 Remote SSH 并不是一个操作系统级 Sandbox。 它最终拿到的权限,就是:

你 SSH 登录这个服务器账号所拥有的权限

例如你通过:

User zx

登录,那么 DSH 的远程工具本质上也运行在:

zx

这个 Unix 用户身份下。 插件当前为了保持本地与远程工具行为一致,采用的是偏向完整访问的策略;README 也明确指出,AHP permission 本身不是 OS sandbox,如果 DSH 策略允许 Full Access,那么同一个 SSH 用户能访问 Workspace 外该 Unix 用户本身有权访问的路径。 所以:

DSH 权限
你的 SSH 用户权限

但并不等于:

DSH 只能访问 Workspace 目录

如果需要更严格的隔离,真正可靠的方法依然是:

专用 Unix 用户
容器
虚拟机

而不是仅依靠 Workspace 路径。


6. 远程服务器到底需要哪些东西?#

测试主机时,你可能会看到类似:

bash ✓
pwsh ×
rg ✓
code ×

第一次看很容易误以为:

是不是四个都必须变成 ✓?

其实不是。


bash#

Linux 服务器上这是最重要的一项。

DSH 需要通过 Bash 来执行:

Terminal window
pwd
ls
python
git
npm
conda

以及 Agent 产生的其他命令。 远端还需要:

base64
mkfifo

来支撑 Shell 和子进程相关功能。 对于正常 Ubuntu Server 来说,这几个一般都已经存在。


7. rg 是什么,为什么 DSH 需要它?#

rg 是:

ripgrep

DSH 会用它完成:

grep
glob
代码搜索
文件搜索

所以:

rg ×

并不是无关紧要的小问题。 如果 rg 不可用,Agent 的代码检索能力会受到明显影响。


8. 最容易踩坑的地方:你明明安装了 rg,DSH 却说没有#

这是我实际遇到的一个问题。 服务器中:

Terminal window
conda activate zx

之后:

Terminal window
which rg

输出:

/home/zhongxu/.conda/envs/zx/bin/rg

并且:

Terminal window
rg --version

完全正常。 看起来 rg 已经安装成功了。 但从本机测试:

Terminal window
ssh Server 'command -v rg'

却什么都没有。 为什么?


9. DSH 使用的不是你平时登录后的交互 Shell#

我们可以测试:

Terminal window
ssh Server 'echo "$PATH"'

得到:

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:...

里面根本没有:

/home/zx/.conda/envs/zx/bin

于是:

交互登录服务器
conda activate zx
rg ✅

但是:

DSH
非交互 SSH
没有 activate zx
rg ❌

问题根本不在 rg

问题在 PATH。


10. 真正的关键:.bashrc 顶部那个 return#

Ubuntu 默认的 ~/.bashrc 通常开头就有:

Terminal window
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac

它的意思是:

如果当前不是交互 Shell,后面的 .bashrc 就不要继续执行了。

而 Conda 初始化一般在文件后面:

Terminal window
# >>> conda initialize >>>
...
# <<< conda initialize <<<

因此 DSH 通过非交互 SSH 执行命令时:

加载 ~/.bashrc
发现不是 interactive
return
Conda 初始化根本没有执行

所以即使:

Terminal window
conda activate zx

后能找到 rg,DSH 还是看不到。


11. 我最终采用的 rg 解决方案#

我不建议让所有非交互 SSH 自动执行:

Terminal window
conda activate zx

因为这样等于把:

python
pip
其他二进制

全部偷偷切换到了 zx 环境。

更干净的方案是:

只把 DSH 真正需要的 rg 暴露出来。

首先创建个人用户命令目录:

Terminal window
mkdir -p ~/bin

然后建立软链接:

Terminal window
ln -sf /home/zx/.conda/envs/zx/bin/rg ~/bin/rg

现在结构就是:

~/bin/rg
└──► ~/.conda/envs/zx/bin/rg

接下来才是这次配置中非常关键的一步。

编辑:

Terminal window
nano ~/.bashrc

在文件最顶部、那个非交互 return 之前增加:

Terminal window
export PATH="$HOME/bin:$PATH"

最终类似:

Terminal window
export PATH="$HOME/bin:$PATH"
# ~/.bashrc: executed by bash(1) for non-login shells.
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac

于是非交互执行过程变成:

SSH
读取 ~/.bashrc
export PATH="$HOME/bin:$PATH"
遇到非交互 return
停止加载其他环境

虽然 Conda 没有激活,但:

~/bin/rg

已经进入 PATH。


12. 验证 rg 是否真正解决#

不要只在服务器里运行:

Terminal window
rg --version

这不能证明 DSH 能看到它。

真正应该从本机测试:

Terminal window
ssh Server 'echo "PATH=$PATH"; echo "rg=$(command -v rg)"; rg --version | head -1'

正确结果应该类似:

PATH=/home/zx/bin:/usr/local/sbin:...
rg=/home/zhongxu/bin/rg
ripgrep 15.2.0

看到这里:

rg=/home/zx/bin/rg

才意味着:

DSH 的非交互远程环境真正能够找到 rg

这也是我认为这一整套配置里最值得记录的坑之一。


13. code × 又是什么意思?#

下一项比较容易误解的是:

code ×

很多人第一反应可能是:

那是不是服务器必须安装完整 VS Code?

并不是。

Remote Workspace 需要的是:

VS Code Agent Host

插件会依次寻找:

1. PATH 中的 code
2. ~/.dsh-remote-ssh/cli/bin/code
3. 已经存在的 VS Code Server cache

这一 fallback 逻辑是插件明确实现的。

所以如果你以前使用过:

VS Code Remote - SSH

服务器可能早就已经有:

~/.vscode-server

14. 检查现有 VS Code Server#

执行:

Terminal window
ls -lah ~/.vscode-server

以及:

Terminal window
du -sh ~/.vscode-server

如果之前经常使用 Remote-SSH,这个目录可能已经非常大。

例如我的服务器已经有多个版本:

~/.vscode-server/cli/servers/
├── Stable-110a328...
├── Stable-a5b500...
├── Stable-c2d1b1...
├── Stable-df53da...
├── Stable-e4c7e7...
└── Stable-8761a5...

这是正常的。

它们本质上是不同 VS Code commit 留下来的 Server 版本。


15. 确认 code-server 是否存在#

可以直接执行与插件搜索逻辑基本一致的命令:

Terminal window
find "$HOME/.vscode-server/cli/servers" \
-type f \
-path '*/server/bin/code-server' \
-perm -u+x \
-printf '%T@ %p\n' 2>/dev/null \
| sort -nr \
| cut -d ' ' -f 2-

如果输出:

/home/user/.vscode-server/cli/servers/Stable-xxx/server/bin/code-server
/home/user/.vscode-server/cli/servers/Stable-yyy/server/bin/code-server
...

说明现有 VS Code Server 可以被插件检测到。

而且插件并不是只尝试最新版本。

它会从新到旧依次尝试不同缓存,因为:

新版 VS Code Server
AHP 协议可能过新
尝试旧版
找到兼容版本

这个 fallback 也是源码明确设计的行为。

因此暂时不要随便把旧的 VS Code Server 全删掉

虽然它们确实可能占掉几 GB 空间,但旧版本有时候恰恰可能成为 Remote SSH 的兼容 fallback。


16. 为什么 code × 也可能完全正常?#

这是另一个值得强调的地方。

如果 DSH 测试主机显示:

bash ✓
rg ✓
code ×

并不能直接得出:

Remote Workspace 不可用

code × 很可能仅仅代表:

Terminal window
command -v code

失败了。

但插件仍然可以进一步找到:

~/.vscode-server/.../server/bin/code-server

并使用现有 VS Code Server 建立 AHP。

所以最终判断标准不应该只是 UI 那几个 ✓ / ×。

真正应该测试:

Remote Workspace 能否:
pwd
读取文件
列目录
grep
glob
执行 bash

如果这些都正常,那么:

VS Code Server fallback 已经工作了。


17. pwsh × 是否需要处理?#

如果你的服务器是 Linux:

pwsh ×

通常完全不用管。

pwsh 指的是:

PowerShell

对 POSIX/Linux Remote Workspace 来说,核心 Shell 是:

bash

上游也明确区分:

POSIX Remote Workspace → bash
Windows Workspace → pwsh

当前远程 Workspace 主要支持 POSIX/Linux SSH 主机。

因此 Ubuntu 服务器最终类似:

bash ✓
rg ✓
pwsh ×
code ×

完全有可能已经可以正常工作。


18. SSH 本身也要先独立验证#

在折腾插件之前,我建议一定先保证:

Terminal window
ssh Server

本身可以正常连接。

例如:

Host Server
HostName 10.122.xxx.xxx
User user
Port 22
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes

先测试:

Terminal window
ssh Server

再进入 DSH。

不要一开始就把:

SSH 配置问题
VPN 问题
密钥问题
DSH 插件问题
rg 问题
VS Code Server 问题

全部混在一起排查。

正确顺序应该是:

SSH
Workspace 映射
bash
rg
VS Code Server / Agent Host
实际 Remote Workspace

19. 最终测试 Remote Workspace#

配置完成后,我比较推荐直接让 Agent 做一个无副作用测试:

请不要修改任何文件,只做环境检查:
1. 输出当前 pwd
2. 执行 command -v rg
3. 执行 rg --version
4. 列出当前工作区一级文件
5. 读取 README.md(如果存在)的前 20 行

如果结果类似:

pwd
/home/user/projects/aigc_detector
command -v rg
/home/user/bin/rg

同时:

目录可以列出
文件可以读取
rg 可以执行
bash 可以执行

那么整条链路实际上已经打通:

DSH Web
Remote Workspace
SSH
VS Code Server / AHP
├── File System
├── Search
├── Bash
└── Background Tasks
Remote Project

20. 最后总结:真正需要理解的几个关键点#

整个配置折腾下来,我认为最容易踩坑的并不是 SSH 本身,而是**“交互环境”和“DSH 远程执行环境并不是同一个环境”**。

尤其是下面这一行:

Terminal window
export PATH="$HOME/bin:$PATH"

以及它必须位于:

Terminal window
case $- in
*i*) ;;
*) return;;
esac

之前这一点,非常关键。

最终我自己的解决思路可以概括成:

第一步:SSH 本身必须能连接
第二步:把远程目录映射成 DSH Workspace
第三步:确认 bash 正常
第四步:安装 rg
第五步:
不要只测试交互式 rg,
而要测试非交互 SSH 能否找到 rg
第六步:
使用 ~/bin 暴露 rg
第七步:
在 ~/.bashrc 的 non-interactive return 前加入
export PATH="$HOME/bin:$PATH"
第八步:
如果 code ×,
先检查已有 ~/.vscode-server,
不要急着重新安装 VS Code
第九步:
实际测试 read / grep / bash / pwd,
而不是只盯着测试页面的 ✓ / ×

配置完成之后,最终得到的是一套我认为很舒服的远程开发结构:

┌───────────────────────────────┐
│ Local Mac │
│ │
│ DSH Web │
│ Model / Provider │
│ Session │
│ Plugins │
│ Skills │
└───────────────┬───────────────┘
SSH / AHP
┌───────────────▼───────────────┐
│ Remote Linux Server │
│ │
│ Project │
│ Data │
│ Conda │
│ Python │
│ Bash │
│ ripgrep │
│ GPU │
└───────────────────────────────┘

本地仍然是自己的 DSH。

服务器仍然是服务器。

项目不需要完整同步到本地。

模型也不需要使用另一套所谓的 remote_* 工具。

你切换的不是工具,而是 Workspace。

这也是 dsh-remote-ssh 这套设计最吸引我的地方。


相关项目#

上游项目:

https://github.com/Yan-Zero/dsh-remote-ssh

我维护的 DSH rc.8 / Web 版本:

https://github.com/Zhong0118/dsh-remote-ssh

我的版本目前主要服务于 DSH Web + Linux SSH Remote Workspace 这一场景,移除了 TUI 相关部分,并针对 DeepSeek Harness 0.1.0-rc.8 做了适配。后续如果继续长期使用这套工作流,也可能在此基础上继续补充 Web 端的体验和功能。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!

赞助

目录