DeepSeek Harness Hub
← 返回列表

vocsong/deepseek-harness-portal

DeepSeek Harnessspec-screened在 GitHub 查看 ↗
需源码安装

一个多租户平台,在单个 Cloudflare Tunnel 后面为每个用户提供一个隔离的 DeepSeek…

暂不能直接安装(需源码编译或环境不满足):仓库缺少 package.json,无法用 dsh 插件安装命令安装。 · 最近上游提交 2026/8/18 · 已提供中文文档

一个多租户平台,用于配置和路由隔离的 DeepSeek Harness (dsh) 实例——每个用户一个容器。

综合分
33.4
GitHub 分
33.4
用户评分
★ Stars
2
周下载量
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add vocsong/deepseek-harness-portal
仓库缺少 package.json,无法用 dsh 插件安装命令安装,改用 GitHub 源安装
数据截至 2026/9/19(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
安装兼容性检查需源码安装

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

npm 包deepseek-harness-portal(未发布到 npm,仅可源码安装)
Node 引擎未声明 engines.node
dsh CLI 依赖未声明 dsh 版本约束
入口文件缺少入口声明

仓库缺少 package.json,无法用 dsh 插件安装命令安装

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

用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动

README

DeepSeek Harness Portal

一个多租户平台,在单个 Cloudflare Tunnel 后面为每个用户提供一个隔离的 DeepSeek Harness(dsh)实例——每个用户一个容器。

Internet
│                      (portal: login, admin, user dashboard)
│  .         (one instance per user)
▼
Cloudflare Tunnel (cloudflared, one named tunnel)
│
▼
Portal (Node + Fastify + SQLite) ── auth + reverse proxy + orchestrator
│
├─► container dsh-   (dsh web on :3000 inside, published 127.0.0.1:18xxx)
├─► container dsh-  ...
└─► ...

Portal 是唯一的认证入口。它负责注册、登录、角色以及每个实例的访问控制。

认证模型

- 注册:邮箱 + 一次性验证码(OTP),注册时可选设置用户名 + 密码(这样新用户可以立即使用凭据登录)。当管理员设置了邀请码时,会强制要求填写邀请码。
- 注册后:个人资料可以更改姓名、用户名、密码和邮箱。更换邮箱需要分别从当前邮箱和新邮箱获取验证码,并会撤销所有其他会话。
- 登录:用户名/密码或“给我发邮件验证码”(OTP 备用方式)。
- 管理员控制(Settings 标签页):邮箱域名白名单、邀请码、OTP 注册开关、密码登录开关。

OTP 发送使用 SMTP(nodemailer),在生产环境中为必需项。只有在明确仅限本地的开发组合 NODE_ENV=development、DOMAIN=localhost 和 OTP_DEV_MODE=true 下才可记录验证码日志;API 永远不会返回 OTP 值。

架构

| 组件 | 位置 | 作用 |
|---|---|---|
| Portal 应用 | portal/ | Fastify 服务器:认证(OTP + 密码、bcrypt、会话 cookie)、管理员/用户 JSON API、静态仪表盘、子域名反向代理 |
| 编排器 | portal/src/orchestrator.js | podman CLI 封装:run/start/stop/rm/logs、端口分配、健康轮询、后台配置 |
| 存储 | portal/data/portal.db | SQLite(better-sqlite3):users、otps、settings、instances、sessions |
| dsh 镜像 | image/Dockerfile | 从已审核的上游提交、一个依赖安全补丁和两个有文档记录的源码补丁构建经过审查的 dsh 镜像;标记为 dsh:47f9438-node24(Debian 13 trixie 上的 Node 24 LTS),并通过其 sha256: 摘要进行部署 |
| dsh 克隆 | dsh/ | 全新的 deepseek-harness 检出(构建上下文,已被 gitignore) |

每实例模型

每个用户恰好获得一个实例(1 user : 1 instance):

- 容器 dsh-,CPU/内存/交换/PID 限制,只读根文件系统 + 有界 tmpfs/logs,无 capabilities,no-new-privileges,显式隔离的 pasta 网络,--restart unless-stopped
- 两个卷:-home(挂载到 /home/dsh —— 用户的可写主目录,包括用于会话、设置和凭据的 $DSH_HOME=/home/dsh/.dsh)和 -workspace(挂载到 /workspace —— 代理的持久化 cwd)
- 发布在 127.0.0.1: 上(绝不暴露到主机之外);门户会代理到它
- 代理将到实例的流量呈现为回环(changeOrigin 将 Host 重写为 127.0.0.1:,并且浏览器的 Origin 被丢弃),以便 dsh 仅限回环的设置/凭据方法可以工作;TRUSTED_HOST=. 仍作为回退传递
- 用户的 DeepSeek API 密钥在其实例内部输入(Settings → Models),并且仅存在于该实例的 home 卷中

对 dsh 的构建时更改(参见 image/Dockerfile)

- image/dsh-security.patch 应用经过审查的传递依赖最低版本以及匹配的冻结 lockfile(生产审计:审查时零已知安全公告)。
- 身份开场白 → "You are an AI agent."(品牌化)。
- 允许 --host 0.0.0.0 → 这是必需的,以便发布的端口能够到达容器内的 dsh(出于 LAN 安全考虑,其 CLI 默认拒绝 0.0.0.0;在容器内,只有回环发布的端口可被访问)。

构建脚本要求使用确切批准的上游提交,并且如果源代码/补丁校验发生漂移就会失败。

使用子域,而非路径

实例使用一级子域(.),而不是 /。有两个原因:

1. dsh 的 SPA 调用 /api 并加载 /assets,这些绝对路径在构建时就被写死 —— 基于路径的路由需要重写 HTML 并拦截 SPA 的绝对 /api 调用(在多标签页情况下很脆弱)。
2. Cloudflare 免费套餐的 Universal SSL 通配符仅覆盖一个标签(.example.com),因此 .. 没有有效的 TLS 证书。-deepseek slug 后缀既保留了品牌,又保持为一个标签。

先决条件

- Podman 以及正在运行的虚拟机:podman machine start
- Node.js 22+ 和 npm
- cloudflared(cloudflared tunnel --version)
- 你账户上的一个 Cloudflare 区域,并且隧道已经过身份验证

设置

1. 克隆 dsh(全新上游)

git clone --depth 1 https://github.com/deepseek-ai/deepseek-harness.git dsh
git -C dsh fetch --depth 1 origin 47f943859bef60e4160492346772ded9b24f765a
git -C dsh checkout --detach 47f943859bef60e4160492346772ded9b24f765a

2. 构建 dsh 镜像

./build-image.sh

始终使用该脚本:它会验证批准的提交和补丁,校验上下文策略,并从干净的 git archive 构建。直接运行 podman build 会绕过这些控制。将脚本打印出的 DSH_IMAGE=sha256:... 行复制到 .env 中;生产环境会拒绝可变镜像标签。

首次构建很慢(pnpm install + 完整 harness 构建);结果约为 2.5 GB。

3. 安装门户依赖

cd portal && npm install && cd ..

4. 配置

cp .env.example .env   # 然后编辑 .env(DOMAIN、INSTANCE_DOMAIN、ADMIN_、SMTP_)

5. Cloudflare 路由(一次性)

cloudflared tunnel route dns  '.'
cloudflared tunnel route dns

隧道配置(~/.cloudflared/.yml):

tunnel:
credentials-file: '~/.cloudflared/.json'
ingress:
- hostname:
service: http://127.0.0.1:8080
- hostname: '.'
service: http://127.0.0.1:8080
- service: http_status:404

cloudflared tunnel --config ~/.cloudflared/.yml run

6. 运行门户

./run-portal.sh

首次启动时根据 ADMIN_EMAIL / ADMIN_NAME / ADMIN_PASSWORD 初始化管理员账户。密码必须显式设置、非占位符,且至少 16 个字符;启动时会拒绝不安全的引导配置。

run-portal.sh 首先应用租户出口防火墙(firewall/apply.sh),如果 Podman 虚拟机未运行则安全失败(fail closed)。

配置(环境变量)

参见 .env.example。重要的变量如下:

| 变量 | 默认值 | 含义 |
|---|---|---|
| NODE_ENV | production | 仅在本地测试时使用 development |
| DOMAIN | example.com | 门户顶级域名 |
| PORTAL_ORIGIN | https:// | 用于变更/CSRF 校验的精确受信任浏览器来源 |
| INSTANCE_DOMAIN | example.com | . 的基础域名 |
| INSTANCE_SLUG_SUFFIX | -deepseek | 追加到 slug 后 |
| COOKIE_DOMAIN | (空)* | 会话 cookie 域(必须覆盖顶级域名和实例) |
| SESSION_ABSOLUTE_TTL_MS / SESSION_IDLE_TTL_MS | 7 天 / 24 小时 | 服务器强制执行的会话生命周期和空闲过期时间 |
| PORT | 8080 | 门户监听端口(cloudflared 连接到此端口) |
| ADMIN_EMAIL / ADMIN_NAME / ADMIN_PASSWORD | (空) | 首次启动管理员;密码必须显式设置且至少 16 个字符 |
| SMTP_HOST / SMTP_PORT / SMTP_USER / SMTP_PASS / SMTP_FROM | (空) | 生产环境 OTP 投递;host/from 必填,认证值需成对提供 |
| OTP_TTL_MS / OTP_MAX_ATTEMPTS | 10 分钟 / 5 | OTP 有效期和每个验证码的尝试上限 |
| AUTH_RATE_WINDOW_MS / AUTH_RATE_BLOCK_MS | 15 分钟 / 15 分钟 | 持久化认证限流窗口/封禁时长 |
| OTP_RESEND_COOLDOWN_MS | 60000 | 每个地址/用途之间 OTP 请求的最小间隔 |
| PORT_RANGE_START / END | 18000 / 18100 | 主机回环端口池 |
| DSH_IMAGE | 必填 | 由 ./build-image.sh 输出的不可变 sha256:... 镜像 ID;生产环境拒绝可变标签 |
| PODMAN_COMMAND_TIMEOUT_MS | 60000 | 每次 podman 调用的子进程超时时间 |
| INSTANCE_CPUS / INSTANCE_MEMORY / INSTANCE_MEMORY_SWAP | 2 / 2g / 2g | 每个实例的计算资源限制 |
| INSTANCE_PIDS_LIMIT | 512 | 每个容器的进程数限制 |
| INSTANCE_NETWORK | pasta | 必需的隔离无根网络模式 |
| INSTANCE_LOG_SIZE / INSTANCE_TMPFS_SIZE | 10mb / 64m | 有界的运行时日志和临时存储 |
| INSTANCE_READ_ONLY_ROOT | true | 以只读根文件系统运行租户容器 |

测试

cd portal && npm test

针对 portal/test/ 中的临时 SQLite 数据库运行隔离的事务性回归测试套件(电子邮件更改证明绑定、尝试次数统计以及唯一性/会话回滚)。它不会触碰实时数据、发送电子邮件,也不要求 Podman。

运维

- 管理员:以管理员身份登录 → 设置选项卡 → 电子邮件域白名单、邀请码、身份验证开关。实例选项卡 → 重新配置/删除、查看日志、使用情况(请求数 + 最后活跃时间)。用户选项卡 → 列出用户。
- 用户:注册(电子邮件 OTP,可选设置用户名/密码)→ 实例自动配置 → 仪表板显示 URL + 状态。实例在启动时自动启动,并在空闲超时后自动停止。
- 启动:https://. —— 门户进行身份验证 + 授权,然后代理到容器。
- API 密钥:在 dsh 内按实例设置(设置 → 模型)。

重启后重新启动

podman machine start    # 1) 容器运行时
cloudflared tunnel --config ~/.cloudflared/.yml run
./run-portal.sh                      # 2) 门户(前台运行;用 nohup/& 包装以在后台运行)

容器带有 --restart unless-stopped;WSL 机器重启后的平台行为仍可能导致它们处于停止状态。门户在启动时会自动启动已授权用户的容器,并在启动时重新排队任何处于 provisioning 状态的实例。run-portal.sh 在每次启动时重新应用租户出口防火墙(幂等);如果你在门户已在运行时重启 Podman 机器,请手动运行 firewall/apply.sh。

故障排除

症状: 租户子域无法加载,容器在 podman ps 中显示 Up,但从 Windows 执行 curl http://127.0.0.1: 失败(而在发行版内部通过 podman machine ssh  'curl http://127.0.0.1:/' 返回 200)。

原因: WSL2 的 localhost 转发器(wslrelay.exe)在经过多次容器停止/启动循环(空闲停止 + 自动启动)后,可能会卡住一个过期的端口转发条目。过期的 wslrelay 进程和孤立的 pasta 进程会不断累积。

修复: 重启 WSL2 VM 并重新配置已停止的租户:

wsl.exe --shutdown
podman machine start
重新配置(或直接启动每个租户;门户会在访问时自动启动)
./run-portal.sh

将 WSL 引擎更新到最新版本(目前因 Windows Installer 重启而被阻止)是针对底层 wslrelay 过期问题的持久修复方案。

安全模型

- 会话 cookie:HttpOnly、SameSite=Lax,当设置了 COOKIE_DOMAIN 时为 Secure;持有者令牌在 SQLite 中以 SHA-256 摘要形式存储,并由服务器强制执行 7 天绝对过期和 24 小时空闲过期。
- 密码:bcrypt。OTP 验证码:加盐 SHA-256,10 分钟过期,尝试次数上限,恒定时间比较;登录/OTP/邀请流程使用持久的按 IP 和按账户限流。
- 每个子域请求在到达容器之前都要经过身份验证(会话)和授权(所有者或管理员);门户 cookie 和网关身份标头在 HTTP/WebSocket 转发之前会被剥离。
- 门户变更操作要求精确的门户 Origin 和每会话 CSRF 令牌;租户同级子域被视为不受信任。
- 实例相互隔离:私有主目录 + 工作区卷、CPU/内存上限、dsh 自带的沙箱。
- 租户出口防火墙:容器无法访问 RFC1918 私有地址范围(你的局域网、10/8、172.16/12);仅允许公共互联网出口。由 Podman 机器上的 nftables 强制执行(firewall/tenant-egress.nft),并由 run-portal.sh 自动应用。
- 门户是唯一的认证层(没有 Cloudflare Access)。

文件

deepseek-portal/
portal/            Fastify 应用 + 静态仪表盘
src/             后端模块(auth、db、otp、mailer、proxy、orchestrator、email-change)
test/            事务性回归测试套件(npm test)
image/             Dockerfile + start.sh + dsh-security.patch(dsh 镜像)
firewall/          租户出口防火墙(nftables)+ apply.sh
dsh/               全新上游克隆(构建上下文,已 gitignore)
build-image.sh
run-portal.sh      应用出口防火墙,然后启动门户
.env.example
README.md
SECURITY_AUDIT.md  完整审计、发现项和修复状态
SECURITY.md        漏洞披露政策

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

💬 加入 DPharness 群聊

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

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