# DeepSeek Harness Docker 部署 本仓库只包含 **Docker 部署封装**,不含 DSH 源码。运行时从 npm 安装官方 [`@deepseek-ai/dsh`](https://www.npmjs.com/package/@deepseek-ai/dsh)。 | | | |---|---| | 构建产出 | 工具链底座(Node 24 / Python 3.11 / gcc / pnpm / rustup 引导),约 750MB(arm64 实测) | | 每次启动 | `npm install -g @deepseek-ai/dsh@latest`,失败则容器退出(无内置 dsh 兜底) | | 宿主机端口 | `3080` | | 数据 | 命名卷 `dsh-data` → `/home/dsh/.dsh`(会话、设置、插件、npm cache) | ## 快速开始 ```bash git clone <本仓库地址> cd DSH docker compose up -d --build docker logs -f dsh ``` 日志中会出现: ```text dsh-entry: installed 0.1.5-rc.1 ← 版本以 npm 上 latest 为准 dsh-entry: forwarding 0.0.0.0:3080 -> 127.0.0.1:3081 dsh web: http://127.0.0.1:3081/?token=<一次性令牌> ``` 1. 把 URL 里的 **`127.0.0.1:3081` 换成 `127.0.0.1:3080`**(或 `服务器IP:3080`) 2. 浏览器打开**一次**带 `?token=` 的地址 → 写入 30 天 cookie 3. 之后直接访问 `http://127.0.0.1:3080/` 即可 国内网络建议在 `docker-compose.yml` 的 `environment` 中启用: ```yaml - DSH_NPM_REGISTRY=https://registry.npmmirror.com ``` > 官方 `@latest` **强制浏览器认证**,没有免 token 开关。`DSH_TRUST_ALL` 只存在于历史 fork 镜像,当前路径无效。 ## 运行示例 已推送镜像(多架构 `linux/amd64` + `linux/arm64`): ```text registry.cn-hangzhou.aliyuncs.com/skymirror/dsh:latest ``` ### 1. Docker Compose(推荐,本仓库源码构建) ```bash git clone <本仓库地址> cd DeepSeekHarnessDocker # 国内网络:取消注释 docker-compose.yml 里的 DSH_NPM_REGISTRY # - DSH_NPM_REGISTRY=https://registry.npmmirror.com docker compose up -d --build docker compose logs -f dsh ``` 常用 compose 子命令: ```bash docker compose ps # 状态 docker compose logs -f dsh # 跟日志(找 token URL) docker compose restart dsh # 改完插件/配置后重启 docker compose down # 停容器,保留 dsh-data 卷 docker compose down -v # 连数据卷一起删(慎用) docker compose build --no-cache # 强制重建镜像 ``` 完整 `docker-compose.yml` 可参考仓库内文件;最小可用示例: ```yaml services: dsh: image: registry.cn-hangzhou.aliyuncs.com/skymirror/dsh:latest # 或本地构建:build: . ports: - "3080:3080" volumes: - dsh-data:/home/dsh/.dsh - ./workspace:/workspace environment: - DSH_HOME=/home/dsh/.dsh - HOME=/workspace - DSH_NPM_REGISTRY=https://registry.npmmirror.com # 远程用 IP 访问时打开(仍需 token cookie): # command: ["--trusted-host", "your-server-ip"] restart: unless-stopped volumes: dsh-data: ``` ### 2. Docker Compose(直接用 ACR 预构建镜像,不 build) ```bash mkdir -p dsh-docker && cd dsh-docker # 把上面的 docker-compose.yml 存到当前目录后: docker compose up -d docker compose logs -f dsh ``` 或一行拉起(无 compose): ```bash docker pull registry.cn-hangzhou.aliyuncs.com/skymirror/dsh:latest docker run -d --name dsh \ --restart unless-stopped \ -p 3080:3080 \ -v dsh-data:/home/dsh/.dsh \ -v "$PWD/workspace":/workspace \ -e DSH_HOME=/home/dsh/.dsh \ -e HOME=/workspace \ -e DSH_NPM_REGISTRY=https://registry.npmmirror.com \ registry.cn-hangzhou.aliyuncs.com/skymirror/dsh:latest docker logs -f dsh ``` 打开日志中的 URL(把 `:3081` 换成 `:3080`)。 ### 3. `docker run` 变体 **钉住 dsh 版本(可复现):** ```bash docker run -d --name dsh \ -p 3080:3080 \ -v dsh-data:/home/dsh/.dsh \ -e DSH_DIST_TAG=0.1.5-rc.1 \ -e DSH_NPM_REGISTRY=https://registry.npmmirror.com \ registry.cn-hangzhou.aliyuncs.com/skymirror/dsh:latest ``` **改宿主机端口(例如 18080):** ```bash docker run -d --name dsh \ -p 18080:18080 \ -v dsh-data:/home/dsh/.dsh \ -e DSH_FORWARD_PORT=18080 \ registry.cn-hangzhou.aliyuncs.com/skymirror/dsh:latest ``` **其它机器通过服务器 IP 访问:** ```bash docker run -d --name dsh \ -p 3080:3080 \ -v dsh-data:/home/dsh/.dsh \ -e DSH_NPM_REGISTRY=https://registry.npmmirror.com \ registry.cn-hangzhou.aliyuncs.com/skymirror/dsh:latest \ --trusted-host 203.0.113.10 ``` 浏览器仍须先用日志里带 `?token=` 的 `http://203.0.113.10:3080/?token=…` 打开一次。 **前台调试(不 detach):** ```bash docker run --rm -it \ -p 3080:3080 \ -v dsh-data:/home/dsh/.dsh \ -e DSH_NPM_REGISTRY=https://registry.npmmirror.com \ registry.cn-hangzhou.aliyuncs.com/skymirror/dsh:latest ``` ### 4. 进入容器 ```bash docker exec -it dsh sh docker exec -it dsh dsh --version docker exec -it dsh dsh plugin --profile web list ``` ## 端口拓扑 官方 `dsh web` 只监听 `127.0.0.1`,并拒绝 `--host 0.0.0.0`。Docker `-p` 打不到容器内 loopback,因此 entrypoint 做 L4 转发: ```text 宿主机 :3080 → 容器 0.0.0.0:3080 (entrypoint 转发) → 127.0.0.1:3081 (dsh web --no-open --port 3081) ``` ```text 浏览器 ──http://host:3080/?token=…──▶ 0.0.0.0:3080 ──▶ 127.0.0.1:3081 │ ┌─────────────────────────┴─────────────────────────┐ │ dsh-data:/home/dsh/.dsh ./workspace:/workspace │ │ 会话/设置/插件/npm-cache agent 工作目录 │ └───────────────────────────────────────────────────┘ ``` **不要**单独 `-p` 映射容器内 `3081`;Docker 映射的应是转发口 `3080`。 ## 配置参考 ### 环境变量(entrypoint) | 变量 | 默认 | 说明 | |------|------|------| | `DSH_PACKAGE` | `@deepseek-ai/dsh` | npm 包名 | | `DSH_DIST_TAG` | `latest` | dist-tag 或精确版本(如 `0.1.5-rc.1`) | | `DSH_NPM_REGISTRY` | `https://registry.npmjs.org` | 安装用 registry | | `DSH_NPM_CACHE` | `$DSH_HOME/npm-cache` | npm cache(卷内,加速重启) | | `DSH_INTERNAL_PORT` | `3081` | dsh 监听端口(仅 loopback) | | `DSH_FORWARD_PORT` | `3080` | `0.0.0.0` 转发端口;与 compose `ports` 一致 | ### 传给 `dsh web` 的参数 entrypoint 固定执行: ```text dsh web --no-open --port $DSH_INTERNAL_PORT ``` compose 的 `command` 会追加在后面。常用: ```yaml # 从其它机器用 IP/域名访问时,声明 Host/Origin 围栏权威(仍需 token cookie) command: ["--trusted-host", "203.0.113.10"] ``` | 不要通过 command 传 | 原因 | |---------------------|------| | `--host 0.0.0.0` | 官方明确拒绝 | | `--port` | 用 `DSH_INTERNAL_PORT` | | `--no-open` | entrypoint 已固定 | ### 改端口 ```yaml environment: - DSH_FORWARD_PORT=8080 ports: - "8080:8080" ``` ### 持久化与工作区 ```yaml volumes: - dsh-data:/home/dsh/.dsh # 会话/设置/插件(保留) - ./workspace:/workspace # agent 工作目录;HOME 指向这里 ``` 插件装在 `$DSH_HOME/profiles//`,**在卷内,重启不丢**: ```bash docker exec -it dsh dsh plugin --profile web add docker restart dsh # 插件变更需重启容器 ``` ## 从其它机器访问 1. **围栏**:Host 为 `http://:3080` 时不是 loopback,需 `command: ["--trusted-host", ""]` 2. **认证**:仍须用日志里的 `?token=` URL 打开一次 3. **安全**:DSH 可执行代码。公网请前置带认证/TLS 的反向代理,不要裸暴露 ## 前置条件 - Docker Engine 20.10+(BuildKit) - Docker Compose v2 - 容器启动时能访问所配置的 npm registry ## 构建说明 ```bash docker compose build # 只装 apt/工具链,无 monorepo 编译 docker compose up -d ``` ### 基础镜像 默认 `ARG BASE_IMAGE=registry.cn-hangzhou.aliyuncs.com/skymirror/node:24.19.0-bookworm-slim`(与 Docker Hub `node:24.19.0-bookworm-slim` 同源)。Docker Hub 不可达时可继续用该 ACR 地址,或自建同步后: ```bash docker buildx build \ --build-arg BASE_IMAGE=<你的registry>/node:24.19.0-bookworm-slim \ --platform linux/arm64 -t dsh:local --load . ``` ### 构建源(国内默认) | 组件 | 默认源 | |------|--------| | apt | 清华 Debian | | npm(构建期 npm/pnpm) | npmmirror | | rustup 引导 | USTC / rsproxy | | pip | 清华 | 可用 `--build-arg NPM_REGISTRY=...`、`APT_MIRROR=...` 覆盖。 ### 清理 buildx 缓存 ```bash docker buildx du docker buildx prune --filter until=24h # docker buildx prune --all ``` ## 镜像内置环境 | 工具 | 版本 | 说明 | |------|------|------| | Node.js | 24.19.0 | 基础镜像 | | npm | 11.17.0 | 构建期升级 | | pnpm | 11.7.0 | `dsh plugin add` 依赖 | | Python | 3.11 | apt;含 pip / venv / Python.h | | gcc / g++ / make | bookworm | 原生模块编译 | | Rust | stable,按需 | 首次 `cargo`/`rustc`/`rustup` 时装入 `dsh-data` 卷 | | git / curl | apt | | 不内置 JDK、Go。需要时进容器安装。 ```bash # 预触发 Rust 安装(可选) docker exec dsh cargo --version ``` ## 不用 Docker ```bash # Node ^22.19 || >=24 npx --yes @deepseek-ai/dsh@latest web npm view @deepseek-ai/dsh dist-tags ``` 本机只监听 `127.0.0.1`,打开日志中的 `?token=` URL。插件管理需 `corepack enable pnpm`。 | | `npx` | 本仓库 Docker | |---|---|---| | 工具链 | 仅本机 Node | Python / gcc / pnpm / Rust 按需 | | 升级 | 每次 `@latest` | 每次容器启动 `@latest` | | 数据 | `~/.dsh` | `dsh-data` 卷 | | 远程访问 | 仅 loopback | `3080` 转发进容器 | ## 仓库布局 ```text Dockerfile 工具链镜像 + entrypoint docker-compose.yml 端口 / 卷 / 环境变量 docker/entrypoint.sh 安装 @latest → 转发 → dsh web docker/ensure-rust.sh Rust 按需安装包装器 DEPLOY.md 本文档 LICENSE GPL-3.0 ``` ## 常见问题 | 现象 | 处理 | |------|------| | 启动慢或立刻退出 | `docker logs`:多半 npm 安装失败。设 `DSH_NPM_REGISTRY=https://registry.npmmirror.com`,或钉版本 `DSH_DIST_TAG=0.1.5-rc.1` | | `authentication required; reopen the URL printed by dsh web` | 正常。用带 `?token=` 的 URL 打开一次;官方包不能免 token | | `GET /` 返回 401 | 同上 | | `/api` 返回 403 | Host 不在围栏:`command: ["--trusted-host", "<你的Host>"]` | | 宿主机 3080 connection reset | 映射应为 `3080:3080`;logs 需有 `forwarding 0.0.0.0:3080 -> 127.0.0.1:3081` | | `--host 0.0.0.0 is intentionally not supported` | 官方限制。不要传该参数,依赖转发 | | 端口占用 | 同时改 `ports` 与 `DSH_FORWARD_PORT` | | `Cannot find module .../dsh/lib/bin.js` | 覆盖了 `entrypoint:`/`command:`,绕过了安装入口;去掉覆盖后重建 | | 插件重启后消失 | 确认插件装在 `$DSH_HOME/profiles`,且 `dsh-data` 卷未挂错 | | 设置了 `DSH_TRUST_ALL=1` 仍要 token | 预期行为。官方包无此变量 | ## 许可 本仓库部署封装为 [GPL-3.0](LICENSE)。上游 DeepSeek Harness 为 MIT,运行时安装的官方 npm 包不受本仓库许可证变更影响。