DeepSeek Harness VPS 私有部署与SSH隧道访问
在Linux VPS上安装DeepSeek Harness,锁定npm版本并了解插件权限。文中解释3080端口为何不能公开,以及如何通过SSH隧道访问无密码Web UI。
DeepSeek Harness 是什么
DeepSeek Harness(dsh)是一种 Node.js 代理运行时,可在 VPS(虚拟专用服务器)上运行。安全的运行方式是将其绑定到 127.0.0.1,再让浏览器通过 SSH(安全 Shell)隧道访问。它会在 3080 端口提供 Web UI(用户界面),而不是运行在终端中。该 Web 服务器本身不要求密码,因此公开 3080 端口后,任何发现它的人都可以获得一个能够读取您的文件并以您的 Linux 用户身份运行命令的代理。
DeepSeek 于 13 August 2026 以 MIT 许可证发布了该项目,npm 包名称为 @deepseek-ai/dsh。项目将自身描述为开发者预览版,并声明预计会有不兼容的变更。下文中的所有版本号都对应 August 2026 的快照,因此在将任何内容复制到重要服务器之前,请先检查代码仓库。
整个设计围绕一个理念展开:所有功能都是插件。模型适配器、工具注册表、会话日志、沙箱、调度器以及代理循环本身,都是加载到同一共享上下文中的插件,并且都可以替换。这里没有一个仅供插件扩展的特权核心。这使 Harness 值得尝试,但真正的风险也正来自这里。
Harness 不是模型
Harness 负责运行 agent 循环。推理在其他位置的模型中进行,因此必须为它提供 API(应用程序编程接口)密钥,或提供您自行托管的模型端点地址,否则任何功能都无法运行。
您可以在 UI 中依次打开 Settings 和 Models 进行配置。目录中为主要 API 提供商(DeepSeek、OpenAI、Anthropic)提供了现成卡片,您只需粘贴密钥。“Add a custom provider”是更灵活的选项:它要求填写提供商 ID、显示名称、基础 URL、API 协议和凭据,并使用 OpenAI 兼容协议。因此,任何实现该协议的网关或本地服务器都可以使用。自定义提供商还可以查询 OpenAI 兼容的 GET /models 端点,自动填充模型列表。
这样即可让 harness 使用同一 VPS 上的模型。Ollama 在 http://127.0.0.1:11434/v1/ 提供 OpenAI 兼容的 API。API key 字段必须填写任意字符串,按约定通常填写 ollama,因为该字段是必填项,之后会被忽略。能否找到一个足够小、可以在您的 VPS 上运行,同时又足以驱动 agent 的模型,是更难回答的问题。Ollama 与 vLLM 作为本地模型服务器的区别决定了这个选择会占用多少 RAM。
在 UI 中输入的密钥只能写入,不能读取。Harness 将密钥存储在 $DSH_HOME/.credentials.yaml 中,并且只在 settings.yaml 中保留凭据引用。$DSH_HOME 的默认值为 ~/.dsh。请将该文件按密码文件保护,因为它确实是密码文件:任何能读取它的人都可以消耗您的 API 额度。
安装前的准备工作
- 一台运行 Ubuntu 24.04 或其他当前版本 Linux 的 VPS,并可通过 SSH 访问
- Node.js 22.19 或 22.x 系列中的更高版本,或 Node.js 24 及更高版本;项目会针对这些版本进行构建和测试
- 一个普通用户账户,而不是
root,因为代理会以启动进程的用户身份运行 shell 命令 - 如果计划安装插件,请确保
pnpm位于 PATH 中,因为插件命令会调用它执行 shell 命令 - 在防火墙和服务商单独提供的网络防火墙上关闭 3080 端口
Ubuntu 自带的 nodejs 软件包版本低于运行测试所需版本,因此应从 NodeSource 或 nvm 安装 Node,不要使用 apt install nodejs。如果 VPS 是新建的,首先加固 SSH 值得花十分钟,因为即将依赖的隧道,其安全性取决于后端 SSH 服务器的安全性。
在 VPS 上安装固定版本的 DeepSeek Harness
node --version
npx @deepseek-ai/dsh@0.1.0-rc.6 webnpx 会下载软件包并运行其 dsh 二进制文件。web 是 --profile web 的别名,用于启动浏览器应用;该进程会输出它监听的地址。默认地址是 http://127.0.0.1:3080。
固定版本。npx @deepseek-ai/dsh web 会在执行时解析 latest 标签当前指向的版本,而该项目已经发布了多个候选版本,并表示即将进行破坏性变更。0.1.0-rc.6 是 13 August 2026 当天 latest 所指向的版本。固定版本后,今天配置的服务器下个月仍会以相同方式运行,因此升级会变成由您主动决定的操作,而不是事后才发现的意外变更。
日常使用时,请安装一次,不要在每次启动时重新解析版本。
npm install -g @deepseek-ai/dsh@0.1.0-rc.6
dsh --profile web --help第二行命令值得执行,因为启动器和 Web 应用使用不同的选项集合。dsh --help 会显示启动器自身的选项。dsh --profile web --help 会显示 Web 应用接受的选项,--port、--host 和可重复指定的 --trusted-host 都属于这一组。
现在确认它监听的地址。
ss -tlnp | grep 3080本地地址列应显示 127.0.0.1:3080。如果显示 0.0.0.0:3080,则表示 UI 可从互联网访问。此时应先停止该进程,再进行其他操作。
为什么绝不能公开发布端口 3080
Web 服务器没有身份验证层。其配置只公开监听主机和监听端口,这就是全部暴露面。对于非回环地址部署,访问控制由单独的可信主机设置负责,该设置不是登录界面。
现在再看这个端口后面的内容。该代理会编辑工作区中的文件并运行 shell 命令,而您的提供商凭据也存放在旁边的磁盘上。因此,开放端口 3080 等同于一个带聊天界面的远程 shell。它以启动该代理的用户身份运行,并附带您的 API 密钥。攻击者不需要利用漏洞。他们只需要知道端口号,而主机上线后,扫描器通常会在数小时内发现端口号。
CLI(命令行界面)也遵循这一原则。截至 0.1.0-rc.6,它有意不支持 --host 0.0.0.0,而是退出并显示用法错误,不会继续启动。这项拒绝行为是安全功能,因此不要寻找移除它的补丁。
隧道不适用时,还有另外两种合理的部署方式。将这台主机加入私有 overlay 网络,使其只拥有您自己的设备能够路由到的地址;自托管 Headscale 控制服务器就能提供这种方式。或者在端口 3080 前面放置反向代理,在请求到达该端口前完成身份验证,例如使用 Authentik 单点登录服务器执行 forward auth。前面没有身份验证的反向代理不属于安全控制。它只是一个更长的 URL。
通过 SSH 隧道访问 Web UI
请在笔记本电脑上运行此命令,不要在服务器上运行。
ssh -N -L 3080:127.0.0.1:3080 you@your-server-L 会在笔记本电脑上打开 3080 端口,并通过加密的 SSH 会话转发连接到该端口的所有流量。127.0.0.1:3080 部分会在服务器上解析,因此连接从回环地址到达 harness,效果与您直接在服务器上操作完全相同。-N 表示不要启动远程 shell,因为您只需要端口转发。
然后在本地浏览器中打开 http://127.0.0.1:3080。如果笔记本电脑上的 3080 端口已被占用,请修改左侧的端口号:ssh -N -L 3180:127.0.0.1:3080 you@your-server,然后访问 http://127.0.0.1:3180。左侧的数字是本地端口,右侧的数字属于服务器,因此只需修改左侧数字。
将其保存到 ~/.ssh/config 中,以后无需再次输入。
Host dsh
HostName 203.0.113.10
User deploy
IdentityFile ~/.ssh/id_ed25519
LocalForward 3080 127.0.0.1:3080之后,ssh -N dsh 会启动隧道。浏览器报告连接被拒绝,通常表示隧道已建立,但远端没有进程监听该端口,因为无论 harness 是否运行,SSH 都会转发该端口。请使用上面的 ss 命令检查服务器。
注销后保持 harness 运行
npx命令会随 shell 一起退出。systemd 用户服务可以持续运行,并在进程崩溃或系统重启后重新启动 harness。
loginctl enable-linger $USER
mkdir -p ~/.config/systemd/user
command -v dshenable-linger很重要,因为用户服务通常会在最后一个会话结束时停止。如果没有它,关闭隧道后 harness 会立即退出。将 command -v dsh 输出的绝对路径写入该单元,因为 systemd 不会搜索登录 shell 构建的 PATH。
[Unit]
Description=DeepSeek Harness web UI
After=network-online.target
[Service]
Type=simple
WorkingDirectory=%h/projects/site
ExecStart=/usr/local/bin/dsh web
Restart=on-failure
RestartSec=5
[Install]
WantedBy=default.targetWorkingDirectory不是装饰性配置。dsh进程会将启动目录用作默认文件系统位置,因此服务在错误目录中启动时,agent 会获得错误的默认工作区。您仍可在 UI 中选择工作区。
systemctl --user daemon-reload
systemctl --user enable --now dsh
systemctl --user status dsh拒绝启动的单元几乎总是因为 ExecStart路径错误,或二进制文件不接受当前 Node 版本;journalctl --user -u dsh -n 50会指出具体原因。同样的模式也适用于让任意 coding agent 在 VPS 上持续运行,故障模式完全相同。
插件可以执行哪些操作
插件是一个模块,可向共享上下文提供服务、类型化事件和可逆操作。以下扩展点尤其值得仔细了解:
- 在
ctx.llm上注册模型提供程序 - 在
ctx.tools上添加面向模型的工具 - 提供
ctx.shell背后的 shell 后端 - 提供
ctx.fs背后的文件系统访问或策略 - 在
ctx.commands上注册用户命令 - 通过
ctx.jobs执行后台任务 - 使用
ctx.sandbox后端封装生成的进程 - 通过
agent/*和tools/*事件拦截请求和工具调用 - 扩展持久会话状态
- 通过
ctx.agents驱动 UI
请从攻击者的角度阅读这份列表。插件可以提供文件系统层和 shell 层,还可以介入模型发起的每次工具调用。插件与这些扩展点之间没有权限确认对话框,因为插件就是普通的 Node 代码,并且与其他所有组件加载在同一进程中。安装插件就等于使用代理的权限运行陌生人的代码,而代理的权限就是您的 Unix 用户权限。
这与将 MCP 服务器连接到 VPS 上的代理 时所做的是同一个信任决策,其中 MCP 指模型上下文协议。这也是为什么在 VPS 上安全运行编码代理时,首先要确定代理所使用的账户,而不是先考虑模型;这同样解释了npm 供应链攻击为何会对服务器造成严重影响:安装步骤本身就是入侵过程,而且不会弹出任何提示。
插件的来源
插件存放在 profile 中。profile 是存储在 $DSH_HOME 下的具名配置,默认路径为 ~/.dsh。每个 profile 目录都包含它安装的外部插件。CLI 会将您的参数直接转发给 pnpm,并将 profile 目录用作工作目录。
dsh plugin --profile web add github:deepseek-harness/turtle-ui
dsh plugin --profile web remove turtle-ui由于参数会原样传递给 pnpm,add、remove、update 和 why 的行为与任何 pnpm 项目中的行为相同。插件可以是 npm 包,也可以是 GitHub 引用。必须先确保 pnpm 位于 PATH 中。在 Node 22 及更高版本中,corepack enable pnpm 会将其放入 PATH。
插件通过 GitHub topic 发现。插件作者会将 dsh-plugin topic 添加到其仓库,浏览该 topic 即可查找现有插件。topic 是作者应用于自己仓库的标签。没有人审核 topic,也没有人对其签名;topic 页面按 star 数量排序,而 star 反映的是受欢迎程度,不代表安全性。
遵循以下四点即可更好地管理插件。安装前先阅读源代码,因为大多数插件都很小,十分钟内即可读完。固定使用确切版本或 commit,不要跟踪分支。使用不拥有其他资源的用户运行 harness,并在您愿意重装的 VPS 上执行。为 agent 使用单独的 API key,并设置独立的支出限额,不要使用生产服务所用的 key。
如果您希望先比较不同设计,再决定采用哪一种,Omnigent 多 agent harness 通过不同结构解决同一问题。使用插件后,各种权衡会更加明显。
首先会出现的问题
Node 版本过旧。 项目要求使用 Node 22.19 以及 22.x 系列中更高的版本,或 Node 24 及更高版本,CI 也会使用这些版本进行测试。旧版运行时会在启动时失败,因为代码使用了旧版不支持的语法和 API。先运行 node --version。
3080 端口已被占用。 可能是第二个 harness、残留进程,或其他同样使用 3080 端口的应用。使用 ss -tlnp | grep 3080 查找占用进程,然后停止该进程,或使用 dsh web --port 3180 在其他位置启动 harness。--port 属于 Web 应用,因此应在 web 之后执行。
浏览器无法通过隧道连接。 确认访问的是 127.0.0.1,而不是服务器的公网地址,因为转发端口只存在于您的笔记本电脑上。然后确认服务器上的 harness 正在监听,因为无论远端是否有程序响应,SSH 都会建立端口转发。
dsh plugin 立即失败。 该命令是 pnpm 的封装,因此如果缺少 pnpm 二进制文件,命令会在任何插件工作开始前停止。
Agent 看不到您的项目。 工作区默认使用进程启动时所在的目录,因此如果某个单元的 WorkingDirectory 是您的主目录,Agent 获得的就是您的主目录。在 UI 中选择工作区,或修正该单元并重新加载。
FAQ
将 DeepSeek Harness Web UI 暴露在端口 3080 上是否安全?
不安全。Web 服务器没有独立的登录机制,其后的代理会以启动进程的用户身份编辑文件并运行 shell 命令,而您的提供商 API 密钥也存储在同一磁盘上。将监听器保持在 127.0.0.1,并通过 SSH 隧道访问。也可以使用私有覆盖网络,或使用反向代理,在请求到达该端口前对每个请求进行身份验证。截至版本 0.1.0-rc.6,CLI 会拒绝 --host 0.0.0.0,并因用法错误退出;这说明作者如何看待这种做法。
我需要 DeepSeek API 密钥,还是可以使用本地模型?
两者都可以,因为 harness 是运行时,而不是模型。在 Settings 中进入 Models,您可以将密钥粘贴到目录提供商卡片中,也可以选择 "Add a custom provider",并提供一个支持 OpenAI 兼容协议的基础 URL。本地 Ollama 服务器在 http://127.0.0.1:11434/v1/ 上响应,并接受 API 密钥字段中的任意字符串。密钥存储在 $DSH_HOME/.credentials.yaml 中,该路径默认为 ~/.dsh/.credentials.yaml。
安装 DeepSeek Harness 插件后,插件实际获得了什么?
获得运行 harness 的账户权限。插件是加载到同一进程中的 Node 代码,而扩展点包括 shell 后端、文件系统层、工具注册表,以及包装每次工具调用的事件。除非插件自行提供沙箱,否则没有任何机制能将插件与这些接口隔离。安装前请阅读源代码,并使用一个不拥有任何重要资源的用户运行 harness。
我应该安装哪个版本?它会持续正常工作吗?
安装固定的确切版本,例如 npx @deepseek-ai/dsh@0.1.0-rc.6 web。13 August 2026 时,latest 标签指向的就是该版本。该项目将自身定位为开发者预览版,并说明预计会出现破坏兼容性的更改,因此未固定版本的命令可能会在不同日期产生不同结果。升级前请检查代码仓库;在版本仍以 0 开头期间,应预期配置键和插件接口会发生变化。