admin d2ef362a98 feat(overlay): 覆盖网络线 序㊾ —— 探针观测面改「两台中继并集」(附 序㊽ 源码/文档补提交)
序㊾(本棒):
- scripts/overlay-probe.cjs:OBS-01 / OBS-08 / OBS-09 的数据源由「只读 47 中继」
  改为「按两台中继取并集」,消除 worker 归属漂移时的假红 / 假 SKIP
  · endpoints 以 network:hostId:port 为键合并,online 取「或」、localPort 取在线那一侧
  · used 按 network/hostId 去重计数(不求和,避免凭空放大在册数)
  · localPort 属中继机回环落点 ⇒ 按归属分机探活(106 侧落点由 106 机上探)
  · derived(OBS-11)保持 47 视角;阈值与判据一律未放宽
  · OBS-16 计数约束:对 47 /status 的读取仍为三次、Δ 只取 47 的 counters;
    对端 106 的采样为独立一次,落在第三次采样之后,不进 (status2, status3] 门窗口
  · 新增 --peer-status-fixture(并集的对端那一半)与「并集不可取证」强制留痕
- 交接单《覆盖网络-序45-低熵块治理-测熵与实现》§16 全节(§8 前前缀逐字未变)
- 参数表 §11.16 补记(§10 现算指纹未变,值格未动)

附(前几棒已完成并已部署、但尚未入仓的源码 / 文档):
- src/net/relay/content/*.ts、src/net/relay/index.ts、main.ts:块级寻址 C 域分离
- src/supervisor/orchestrator.ts、src/worker/agent.ts:日志采集与巡检(方案 C)
- test/overlay-content.test.mjs:随附用例(npm test = 200 pass / 0 fail / 1 skipped,Node 22)
- scripts/dshlog.mjs(跨机日志取证)、scripts/overlay-entropy.cjs(熵探针)
- dsh-server-docs/04-调整方案/129、133;INDEX.md / docs-manifest.json / 交接单 README 登记
2026-09-19 05:35:35 +08:00

dshs

📌 本部署的两处文档别混(档案 19 §C10)

  • docs/(本仓库内)= 仓库自带 7 篇(blueprint / deployment / k8s-deploy …)——不要往这里写我们的改造记录;
  • 本项目的改造文档库在另一仓库:[email protected]:maogeigei/dsh_shenxian_doc.git(服务器镜像 /opt/dsh/docs,root 600), 含档案 01–26、DEPLOY-本部署.md(构建/部署/回滚)、ops/(nginx 与切换脚本)、scripts/(运维工具)。 运维排障先看 DEPLOY-本部署.md 与档案 02 附录 C。

面向公网的多租户 DSH 托管平台 —— 部署到一台公网服务器后,多个用户注册并经管理员审核,各自获得一套相互隔离的 DeepSeek Harness(DSH)环境,随时通过域名安全访问(已适配手机端)。

以 DSH 插件市场 的 cordis-plugin 形态分发,遵守 STANDARD.md。

它解决什么

DSH 本身是单用户本地工具:没有认证、没有多租户隔离、Web 远程访问缺认证层。dshs 在其之上补一层服务端登录 + 多租户编排:

用户浏览器
   │ HTTPS
   ▼
nginx(TLS 终结,主域 + *.子域 通配)
   ▼
编排服务 dshs(Fastify,单进程)
   ├─ 认证 / 审核 / 管理台 / 网页桌面 / 域名 API
   └─ 按 Host 或 /u/<userId>/dsh/* 路由
        └─ 反向代理 → 各用户的 DSH 子进程(只绑 127.0.0.1 动态端口,不出公网)

流程:管理员审核注册用户 → 每个用户落到自己的文件桌面 → 按文件夹启动 DSH → 通过域名访问,彼此文件隔离。

核心能力

能力 说明
登录与审核 bootstrap-admin 创建首个管理员;注册后需审核通过才能登录;禁用用户会同时删除其会话并停止运行中的 DSH
每用户隔离 DSH 主 DSH 常驻对外服务;崩溃时按需拉起一次守护 DSH 修复并自动重启主实例
网页桌面 文件浏览 / 新建 / 上传;按文件夹启动 DSH;所有路径经「词法包含 + 符号链接分量」双重围栏校验
每文件夹插件 自动检测该用户 profile 已安装的插件,按文件夹勾选启用,持久化并注入 cordis patch
多形态访问 默认子路径 /u/<userId>/dsh/;每用户子域名 <用户名>.<baseDomain>(HTTP + WebSocket);自定义域名 + nginx server {} 生成接口
凭据隔离 每用户命名 API 密钥库,AES-256-GCM 加密落库(references-not-secrets);换 key 自动重建实例;spawn 只注入当前启用的 key

部署形态(二选一)

同一套代码,靠 DSHS_DEPLOY_MODE 切换:

模式 A:直接部署(单服务器) 模式 B:K8s + 容器化
形态 单机裸机,child_process + setuid/iptables 多机 ACK,每用户独立 Pod
数据 SQLite(本机文件) PostgreSQL(CloudNativePG)
隔离 软隔离 / OS 账号硬隔离 Pod 网络 + SecurityContext + NetworkPolicy
弹性/HA 无(单点) 控制面 3 副本 + leader election,DSH Pod 自动重建
交付 git clone + 脚本 kubectl apply -f deploy/

模式 B(K8s)已于 2026-09-15 下线:K8s 后端代码从本仓移除(备份在 D:\github\_dsh_shenxian_K8s后端备份_20260915\),deploy/ 清单与设计文档保留作为未来可选路线;当前生产形态为模式 A 单机部署。历史实现(每用户 DSH Pod + tcp-bridge sidecar + file sidecar(8082)+ Headless Service + NetworkPolicy + 控制面 3 副本 + Lease 选主 + reconcile)见 K8s 部署教程 与 踩坑记录。

快速开始(模式 A)

前置:Linux 服务器、Node ^22.19 或 ≥24、已安装 DSH CLI(npm i -g @deepseek-ai/dsh)。完整的生产流程(systemd / DNS / 通配证书 / nginx)见部署教程。

git clone https://work.alotbuy.com/maogeigei/dsh_shenxian.git
cd dshs
npm install && npm run build            # tsc → lib/

# 1) 创建首个管理员(用它登录管理台)
node lib/cli.js bootstrap-admin --username admin --password '<强密码>' --db ./dev.local.db

# 2) 启动编排服务
node lib/cli.js --port 3080 --db ./dev.local.db

打开 http://127.0.0.1:3080/:

  1. 用 admin 登录进入管理台;
  2. 另开浏览器注册一个普通用户 → 回管理台点「通过」;
  3. 该用户重新登录进入桌面 → 上传文件 / 建文件夹 → 点「在此文件夹启动 DSH」;
  4. 首次使用在桌面的「管理密钥」里填入自己的 DeepSeek API Key(加密存储;未设置时 DSH 能启动但无法调用模型)。

⚠️ 本地试跑可以验证登录 / 审核 / 桌面 / 启动全链路;但要打开 DSH 聊天界面,需要配置域名与每用户子域名(BASE_DOMAIN + COOKIE_DOMAIN + nginx 通配,见部署教程第 6–9 步)——DSH 的 SPA 使用绝对路径,纯子路径方式加载不了静态资源。

配置

环境变量均可省略;同名 CLI flag(--port / --db / --isolation-mode 等)优先级更高,全部见 src/config.ts 与 node lib/cli.js --help。

环境变量 默认 说明
DSHS_PORT 3080 编排服务绑定端口(nginx 上游)
DSHS_DATA_ROOT ~/.dshs 每用户 home/workspace 根(生产 /var/lib/dshs)
DSHS_DSH_BIN dsh 子 DSH 可执行文件(建议绝对路径,systemd 下 PATH 精简)
DSHS_ISOLATION_MODE soft soft 软隔离 / account 账号级硬隔离(Linux,需 root)
DSHS_BASE_UID 100000 账号级隔离的 uid 基数
DSHS_PORT_GUARD false iptables owner-match 端口守卫(Linux+root):阻止同机其他账号直连各用户 DSH 的回环端口;不支持的环境下开启会拒绝启动(fail loud)
DSHS_SECURE_COOKIES false HTTPS 部署设为 true(cookie 加 Secure,SameSite=None 以跨子域共享)
DSHS_BASE_DOMAIN 空 每用户子域名的基域(如 dsh.example.com);空 = 仅子路径访问
DSHS_COOKIE_DOMAIN 空 会话 cookie 的 Domain(如 .dsh.example.com,注意前导点);空 = host-only
DSHS_SESSION_TTL 604800 会话有效期(秒,默认 7 天)
DSHS_MAX_UPLOAD 25MB 上传请求体上限(base64 JSON)
DSHS_PACKAGE_DIR (自动探测) 平台内置 dsh 的包根。默认按序探测:DSHS_DSH_BIN 解软链反推 → /usr/local/lib/node_modules、/usr/lib/node_modules → npm root -g。⚠️ npm i -g 的落点随发行版变(发行版包管理器装的 Node 常落 /usr/lib/node_modules),写死会让「模型设置」的厂家目录与「插件兼容性预检」静默失效(无报错、只剩降级行为)⇒ 探测失败时才需要显式设它。
DSHS_COMPAT_ROOT (= DSHS_PACKAGE_DIR) 同上的旧名(兼容);同时接受 DSH_PACKAGE_DIR / DSH_COMPAT_ROOT(导出侧命名)
DSHS_PI_AI_DATA_DIR (自动探测) @earendil-works/pi-ai 的厂家目录数据位置(<包根>/node_modules/@earendil-works/pi-ai/dist/providers/data);一般无需设置
DSHS_RESTART_BACKOFF 1000 子 DSH 崩溃后的自动重启延迟(毫秒)
DSHS_ENABLE_PATCH false 是否向子 DSH 注入 --patch(运行时插件 + 每文件夹插件;旧版 dsh 不支持时可关)
DSHS_SECRET 自动生成 每用户密钥库的加密主密钥;未设置时生成并持久化到 <dataRoot>/secret.key(0600)
DSHS_DEPLOY_MODE local local 单机 / k8s 每用户 Pod(模式 B)
DSHS_DB_URL 空 Postgres DSN;设置即启用 Postgres(k8s 必填)
DSHS_NAMESPACE dsh (k8s)每用户资源所在命名空间
DSHS_DSH_IMAGE 空 (k8s 必填)每用户 DSH Pod 镜像
DSHS_CONTROL_PLANE_IMAGE 空 (k8s 必填)file sidecar / tcp-bridge / init 容器镜像
DSHS_IMAGE_PULL_SECRET dsh-acr-pull (k8s)生成 Pod 的拉镜像 secret
DSHS_EGRESS_CIDRS 空 (k8s)每用户 Pod 443 出站白名单 CIDR;空 = 全网(始终排除私网段与 169.254.169.254)
DSHS_K8S_SERVICE_ACCOUNT dsh-orchestrator (k8s)控制面 ServiceAccount

文档

文档 内容 什么时候读
部署教程(模式 A) 从零到公网可用:Node / DSH / systemd / DNS / HTTPS / nginx 第一次部署单机版,照着做即可
硬隔离教程 每用户独立 OS 账号(setpriv 降权),生产环境建议开启 模式 A 跑通后的进阶加固
域名配置示例 主域 + 每用户子域 + 自定义域名的 nginx 配置 配置域名 / 排查路由问题
常见问题排查 502 / 404 / 401 / 403 / SSL / 端口冲突,按现象索引 出错了先来这里对现象
K8s 部署教程(模式 B) ACK + CNFS + CNPG 分步部署(多机 HA) 要部署容器化多机形态
K8s 踩坑记录 模式 B 实机部署的坑与根因(镜像源 / 存储 / 网络 / 备案) 模式 B 部署卡住时查
技术蓝图 权威技术设计:拓扑 / 双 DSH / 数据模型 / API / 安全模型 想了解原理或参与开发
PoC 实验记录 k8s 关键假设的四项实测(RWX / socat / NetworkPolicy / CNPG) 评估模式 B 可行性时
代码分层与依赖方向 四层划分 + 依赖方向规则 + 三条工程纪律(契约前置 / 模块头注释 = 索引) 动手改 src/ 前读一遍,尤其新增模块或目录时

学习路线:模式 A 先读「部署教程」跑通 → 再看「硬隔离」加固,出问题查「常见问题排查」;模式 B 直接从「K8s 部署教程」开始,卡住查「K8s 踩坑记录」。

开发

npm install          # pnpm/npm 均可;Node ^22.19 || >=24
npm run typecheck    # tsc --noEmit
npm test             # 构建 + node:test 单测(DB 双后端 / k8s spawner / leader / fs 围栏)
npm run smoke        # 及 smoke:* 系列:对运行中的服务做端到端冒烟(scripts/smoke*.mjs)

安全

  • 会话:不透明随机 token,仅 SHA-256 哈希落库;cookie HttpOnly + SameSite,HTTPS 下加 Secure。
  • 密码:scrypt 加盐哈希,常数时间比较。
  • 密钥:每用户 API key 以 AES-256-GCM 加密落库,主密钥来自 env 或 <dataRoot>/secret.key(0600)。
  • 路径:所有文件操作先做词法包含校验,再逐段拒绝符号链接分量,防止越出用户根目录。
  • 隔离分层:软隔离(默认)→ 账号级硬隔离(OS 账号 + setpriv 降权,0700 真正生效)→ 端口守卫(iptables owner-match)→ k8s Pod 边界(non-root / drop ALL / 只读 rootfs / NetworkPolicy)。
  • 审计:注册 / 登录 / 审核 / 改密钥等动作写入 audit_log。

细节与威胁模型见技术蓝图 §7、硬隔离教程。

问题反馈与支持

这是我开发的第一个正式项目,功能可能还不够完善,非常欢迎大家提出意见和反馈! 如果你在使用过程中遇到问题,或者有改进建议,欢迎提交 Issue:

  • 🐛 遇到 Bug:请描述你的复现步骤、报错信息、以及运行环境(系统/DSH 版本等)
  • 💡 功能建议:请说明你的使用场景和你期望的效果
  • 📖 文档疑问:指出 README 中看不懂或描述不清的地方

我会尽量在 1~2 天内回复,确认有效的问题会尽快修复并发布更新。 感谢你的支持!🌟

许可证

双授权(两条平行的许可选择;商业轨不是对开源许可附加的限制):

轨 许可证 适用场景
轨 1(默认) GNU AGPL-3.0 个人使用 / 学习 / 研究 / 评估 · 未修改构建的内部部署 · 已按 AGPL 披露源码的修改版
轨 2(商业) 商业授权(中文) | EN 对外提供闭源托管服务 · 嵌入闭源产品对外分发

商业使用在两条轨下都允许 —— 区别只在源码披露义务:AGPL-3.0 §13 要求把修改版(含网络服务的使用者)对应的源码提供给使用者。不愿承担该义务就走轨 2,条款、期限、部署形态与费用由双方签署的协议约定(那是一份邀约谈判文件,本身不构成授权),联系 [email protected]。

上游 DeepSeek Harness 采用 MIT,本仓库不包含、不分发其代码(运行期以独立进程调用)⇒ 其条款不受上述两轨影响。

S
Description
No description provided
Readme AGPL-3.0
4.4 MiB
0 Stars 1 Watchers 0 Forks
Languages
TypeScript 46.1%
JavaScript 43.9%
Python 4.1%
Shell 2.9%
HTML 2.6%
Other 0.4%