Skip to main content

DeepSeek Harness 部署方案

已确认项目身份与全部部署参数(官方仓库、npm 版本、Node 要求、启动参数、凭据解析)。以下是 Ubuntu 24.04 的部署方案:


项目与最新版本

  • DeepSeek Harness(dsh:DeepSeek 官方开源 agent 框架,采用“一切皆插件”架构(基于 Cordis)。仓库:deepseek-ai/deepseek-harness,文档:官方文档站
  • 最新版本:npm latest = 0.1.5-rc.1(2026-09-10 发布);next 通道 = 0.1.5-rc.2(最新)。处于开发者预览阶段,会有破坏兼容性的变更,部署时建议钉住版本号。
  • 运行要求:Node.js ^22.19.0 || >=24.0.0(package.json engines),Ubuntu 24.04 上推荐 Node 24 LTS
  • 默认端口http://127.0.0.1:3080

推荐部署形态

  • npm 全局安装 + systemd 守护dsh web 本身只监听本机,适合再套一层 nginx 反代 + HTTPS。
  • 不建议用 Docker:官方维护者指出容器路线有已知坑(pnpm 符号链接、node-pty 等原生模块与 musl/glibc、profile patch 被卷挂载覆盖),npm 直装最稳。
  • 生产建议:127.0.0.1 回环绑定(webserver 无内置 TLS/鉴权),远程访问走 SSH 隧道或 nginx+HTTPS。

部署步骤

1. 前置准备(Ubuntu 24.04)

sudo apt update && sudo apt upgrade -y
sudo apt install -y curl ca-certificates git ufw
# 全程用非 root 的 sudo 用户执行

2. 安装 Node.js 24 LTS(NodeSource)

curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
sudo apt install -y nodejs
node -v   # 必须 >= v22.19,推荐 v24.x
npm -v

3. 创建运行用户与工作区目录

sudo useradd --system --create-home --shell /usr/sbin/nologin dsh
sudo mkdir -p /srv/dsh/workspace
sudo chown -R dsh:dsh /srv/dsh
# 启动时所在目录 = 默认 workspace 根目录(Web UI 里还需手动“选择工作区”)

4. 全局安装 DeepSeek Harness(钉住版本)

sudo npm install -g @deepseek-ai/dsh@0.1.5-rc.1
dsh --version        # 预期 0.1.5-rc.1
dsh --help

想用最新 rc.2 就装 @deepseek-ai/dsh@0.1.5-rc.2。CLI 参数:dsh --profile webweb 是别名),web 应用参数需放在其后:--host(仅 127.0.0.1/0.0.0.0)、--port、可重复的 --trusted-host--no-open

5. 配置 DeepSeek API Key(无交互方式)

凭据解析顺序:进程环境变量 → $DSH_HOME/.credentials.yaml → 调用目录 .env$DSH_HOME/.env($DSH_HOME 默认 ~/.dsh)。Web 搜索使用 DEEPSEEK_API_KEY。推荐直接在 systemd 里注入环境变量(第 6 步会用)。

手动方式也可以:启动后浏览器打开 http://127.0.0.1:3080设置 → 模型 → DeepSeek 卡片填 Key(密钥只写,存于 $DSH_HOME/.credentials.yaml)。模型变更立即生效,无需重启。

6. systemd 服务

# /etc/systemd/system/dsh.service
[Unit]
Description=DeepSeek Harness Web UI
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=dsh
Group=dsh
WorkingDirectory=/srv/dsh/workspace
Environment=DSH_HOME=/home/dsh/.dsh
Environment=DEEPSEEK_API_KEY=sk-你的密钥
ExecStart=/usr/bin/dsh web --no-open --host 127.0.0.1 --port 3080
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now dsh
journalctl -u dsh -f          # 观察 "dsh web:" URL 行(内含进程 token,属敏感信息)
curl -sI http://127.0.0.1:3080/ | head -1   # 预期 HTTP/1.1 200

dsh 不在 /usr/bin,用 which dsh 修正 ExecStart

7.(可选)nginx 反代 + HTTPS(远程访问必做)

# /etc/nginx/sites-available/dsh
server {
    listen 80;
    server_name dsh.example.com;
    location / {
        proxy_pass http://127.0.0.1:3080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;      # WebSocket 必需
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
sudo ln -s /etc/nginx/sites-available/dsh /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d dsh.example.com

浏览器同源策略要求:反代后需把域名加入可信主机,否则 WebSocket 连不上 → 在服务参数追加 --trusted-host dsh.example.com(重启生效)。需要登录密码可选装社区插件 dsh-webui-auth;自己只想内网用的也可以不加反代,直接 ssh -L 3080:127.0.0.1:3080 user@server 隧道访问。

8. 防火墙与验收

sudo ufw allow OpenSSH && sudo ufw allow 80/tcp && sudo ufw allow 443/tcp && sudo ufw enable

验收:浏览器打开 https://dsh.example.com → 设置→模型配 Key → 选择工作区 → 发一条任务(例如“Summarize this repository”)→ 确认能读文件、跑命令、委派子任务。

运维与注意事项

  • 升级:开发者预览迭代快,升级前备份整个 $DSH_HOME(settings.yaml.credentials.yamlprofiles/、会话库),再 sudo npm install -g @deepseek-ai/dsh@<新版本>;先看 npm 发布说明和 SAFETY.md
  • 安全:保持回环绑定;启动 URL 里的进程 token 是 API/WebSocket 的认证凭据,注意别把完整 URL 打进日志/截图;密钥只写入 $DSH_HOME/.credentials.yaml,建议 chmod 6000.0.0.0 直绑无 TLS 无鉴权,谨慎。
  • 扩展:一次性任务用 dsh --profile headless "任务文本";插件管理 dsh plugin --profile web add <包>(需 pnpm,sudo corepack enable && corepack prepare pnpm@latest --activate);国内网络需代理时见文档 network-proxy

现状确认:服务器没有 pnpm(需要用 corepack/npm 启用),dsh plugin 必须带 --profile。给你一套可直接照抄的完整示例——以官方插件 Codex 子代理(@deepseek-ai/dsh-subagent-codex 为例:

第一步:装 pnpm(dsh 插件管理依赖它)

sudo npm install -g pnpm@11.7.0     # 项目本身用的 pnpm 11.7.0
pnpm --version                       # 验证

第二步:安装插件到 web 配置

sudo -u dsh /usr/bin/dsh plugin --profile web add @deepseek-ai/dsh-subagent-codex

要点:

  • 必须用 sudo -u dsh 跑(profile 在 /home/dsh/.dsh/profiles/web 下,以 dsh 用户运行才能读到正确的 DSH_HOME
  • --profile web 指定装到哪个配置(还有 headlesssdkacp 或自定义 profile)
  • 该命令等价于在该 profile 目录里执行 pnpm add,装完会自动把包写进 dsh.profile.bundles(因为包的 package.json 声明了 "dsh": {"bundle": {"patch": "./cordis.patch.yml"}}

第三步:重启服务让新 bundle 挂载

sudo systemctl restart dsh
dsh-url        # 重启后 token 变了,取新访问地址

第四步:验证

sudo -u dsh /usr/bin/dsh plugin --profile web list        # 已安装列表
sudo -u dsh env DSH_HOME=/home/dsh/.dsh /usr/bin/dsh --profile web --dump-config | grep -i subagent

Web UI 里新建会话后,Agent 面板会出现 Codex 子代理提供方(实际可用还要求服务器上装了 Codex CLI 并完成登录)。

其他“装插件”的形态(顺带说明)

  • 移除sudo -u dsh /usr/bin/dsh plugin --profile web remove @deepseek-ai/dsh-subagent-codex,然后重启
  • 本地/社区插件... plugin --profile web add <npm包名>,或本地目录 ... add /path/to/plugin(GitHub 上带 dsh-plugin topic 的都是生态插件)
  • 可选覆盖层(非 npm 包):官方 config/examples/ 里的 github-review、schedule、mcp-memory 是 cordis patch 文件,用 dsh --profile web --patch ./xx.yml 或写入 cordis.patch.yml,不需要 pnpm

需要我直接在服务器上把 pnpm 和这个 Codex 子代理插件装上吗?装完我会重启并给你新的访问地址。

核实完毕,关键事实已确认:会话库在 $DSH_HOME/sessions/<工作区>/ 下,一个进程只有一个 token、一份会话库、一份设置——这就是"所有人会话互相可见"的根本原因(当前版本 Web 版是单用户设计,没有内置账号体系)。

隔离方案:每人一个独立实例(推荐)

核心思路:每用户 = 独立 DSH_HOME + 独立端口 + 独立 token + 独立工作区,互不共享任何状态。以给 alice 开一个为例:

1. 建独立系统用户与工作区(文件系统这一层也隔离)

sudo useradd -m -s /usr/sbin/nologin alice
sudo mkdir -p /srv/dsh-alice/workspace
sudo chown -R alice:alice /srv/dsh-alice

2. 新建 systemd 实例(独立 DSH_HOME、独立端口 3081、独立密钥)

# /etc/systemd/system/dsh-alice.service
[Unit]
Description=DeepSeek Harness Web UI (alice)
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=alice
Group=alice
WorkingDirectory=/srv/dsh-alice/workspace
Environment=DSH_HOME=/home/alice/.dsh
Environment=DEEPSEEK_API_KEY=sk-alice自己的密钥
ExecStart=/usr/bin/dsh --profile web --no-open --host 127.0.0.1 --port 3081
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload && sudo systemctl enable --now dsh-alice

3. nginx 给它单独开一个端口(dsh 不让直接绑 0.0.0.0)

# /etc/nginx/sites-available/dsh-alice
server {
    listen 8081;                 # alice 专属入口
    location / {
        proxy_pass http://127.0.0.1:3081;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
    }
}

启用后 sudo nginx -t && sudo systemctl reload nginx

4. 给 alice 发登录地址(每个实例 token 独立)

sudo -u alice env DSH_HOME=/home/alice/.dsh /usr/bin/dsh-url   # 或从 journalctl 取

Alice 打开 http://192.168.4.17:8081/?token=<她的token>,她只会看到自己的会话、设置、密钥;Bob 用 8082/3082 同理。各自实例记得加 --trusted-host 192.168.4.17(如果和共享实例一样用 IP 访问)。

为什么不建议其他做法

    单实例 + 密码插件(dsh-webui-auth:只能挡陌生人,登录后仍是同一个 token/同一份会话库,做不到会话隔离 单实例内分工作区:会话虽按工作区目录存放($DSH_HOME/sessions/...),但任何人拿到 token 都能切到任意工作区查看/操作,代理也能读其他目录,隔离形同虚设 共享 DSH_HOME 跑多个 profilesessions、设置、凭据都在同一个 $DSH_HOME 下,仍互相可见

    安全边界提醒

    这个方案保证的是会话/设置/入口隔离。如果用户之间不完全互信,还需要:

      各自独立工作区目录 + 独立 OS 用户(agent 以该 OS 用户执行命令,读不到别人的目录) 每个实例的 token 只发给对应的人;局域网里 token 即权限

      需要我直接在服务器上把 alice 这个实例(用户、目录、unit、nginx 端口、token)完整建好吗?建好后把她的访问地址单独给你。