- 新增 04-调整方案/103-112:可行性评估 · 全球架构复盘 · 骨干层方案 · 百台推演 v2 · 千台全场景推演 · 游戏专项 · 游戏网络与群聊上限调研 · 答疑(群聊/备份/迁移/保密) · 补遗与参考方案 · 九大瓶颈落地方案 - 每份按 交接单/README.md §二 8 段改写(目标/只读前置/范围/决策点/ 步骤/验收/回滚/回报格式)+ 头部状态标注(📋 规划态 · 未实施) - 技术内容不变:附录 A 逐字保留原文全文(仅去其一级标题),已逐份校验字节一致 - 登记:INDEX.md §二 +10 行、03-路线图与待办.md §二 +1 行 - 收尾:docs-audit.py 退出码 0(无 P0)· docs-manifest.py 已刷新 - 本轮零代码、零服务器改动;⛔ 未 push - 占号:103-112(先原子 mkdir .lock-<NN> 再写)
23 KiB
103 · 客户端安装与覆盖网络互联 · 可行性评估
- 日期:2026-09-16 | 状态:📋 规划态 / 未实施(本轮零代码、零服务器改动;本档=设计单,尚未开跑)
- 来源:工作区根
可行性评估_客户端安装与覆盖网络互联_20260916.md(2026-09-16 转为正式档案,正文见 附录 A) - 层级:决策层 · 总纲(本线其余 9 份档案的共同前置)| 关联:档案 104 · 106–112
- 触发(用户原话):「当前项目是否可以改造为支持服务部署以及客户端安装(客户端壳套服务器项目),让他们通过覆盖网络互联」
TL;DR ✅ 可行,且现有架构已给出约 80% 的形状 —— T08 集群化已经把「一台机器 = 一个可被平台拨入的执行体」定义完了, 并已有两条现成能力正好解决「没有公网 IP」:①
soft隔离模式下实例只是一个普通子进程(不需 root / bwrap / systemd); ② Worker 用拨出式 SSH 反向隧道接入 Manager —— 节点本来就不需要公网 IP。 真正的缺口 4 条:客户端运行时落点 · 节点身份(现为共享令牌)· 信任模型反转 · 分发与版本矩阵。
一、目标
判定「平台能否支持『服务部署 + 客户端安装 + 覆盖网络互联』」,并给出可增量落地的形态与顺序、缺口清单、未验证项诚实清单。 可判定「做完了没有」= 产出 ① 形态结论(A/B/C 三档取舍)② 缺口 4 条 ③ 若走 B 档的 6 步落地顺序(每步可单独回滚)。
二、只读前置
执行前必须先核实的 5 条事实(均已在本轮取证过,给出可复跑命令):
| # | 事实 | 核对方式(期望输出) |
|---|---|---|
| 1 | soft 是默认隔离档 ⇒ 实例 = 裸子进程 |
grep -n "isolationMode" src/config.ts → 'soft' | 'account',默认 soft |
| 2 | soft 下不 bwrap / 不 setpriv / 不 systemd-run | sed -n '660,665p' src/supervisor/orchestrator.ts → 直接 spawn(command,args) |
| 3 | Worker 走拨出式反向隧道(节点无需公网 IP) | sed -n '147,155p' src/worker/tunnel.ts → ssh -O forward -R <port>:127.0.0.1:<port> |
| 4 | 全仓仅一处平台分支 | grep -rn "process.platform" src → 1 处(src/supervisor/firewall.ts) |
| 5 | 节点身份现为共享令牌 + bearer 比较(无吊销) | 读 src/worker/agent.ts 头部注释(自陈「仅内网 + nft 白名单」) |
三、范围
- 改什么:仅新增(新客户端形态 + 新 Spawner 实现 + 新节点身份机制)。服务端现有路径不动。
- 不动什么:⛔ 不改官方 dsh 主程序与缓存(R2)|⛔ 不改管理面(门户 / DB / 归属 / 租约留在服务器)|⛔ 本轮不动服务器、不改代码。
- 红线约束:R5(权限只准收窄 —— 客户端形态下不得下发平台级凭据)|R2|R1(不自动升级 dsh)。
四、决策点
已定
- 形态已拍板 = 单机自用(用户原话:「考虑用户自己使用就可以了,不用考虑当作服务器 其他人访问」)⇒ 本档 §三 的 A/C 两档「多人维度」已放弃,三档表保留为历史决策依据,不再是待拍板项。
- 地基 =
soft隔离档(用户已定:「隔离档保持默认 soft」)—— 三份客户端文档同向。
历史决策依据(本档 §三,已不再是开放问题):A 只做壳(覆盖网络用不上)|B 自带实例(本档倾向)|C 客户端当集群 Worker(需强身份 + 重划合规边界)。
待执行会话复核(非上抛项):soft 模式在 Windows / macOS 上的实际隔离强度与可运行性 —— 本档已实测修正:真正的硬阻塞不在 dsh 运行时,而在平台自己的启动方式(裸名 spawn('npm') 在 Windows 报 ENOENT;显式 .cmd 被 Node 拒 EINVAL;改 cmd.exe /c 或 shell: true 即通)⇒ 代价 = 一处调用方式。
五、步骤(若走 B 档;每步自带一次验证)
- 验证 dsh 在 Windows / macOS 可运行性(只读 + 本地装,不动服务器)→ 验证:客户端能起实例 + 实例内 bash 工具可用。
- 客户端节点代理(复用 agent 协议、落
soft)—— 先只做/healthz/launch/stop/fence→ 验证:台账式幂等(同operationId重放不产生副作用)。 - 通道:先用现有拨出式 SSH 反向隧道打通(零新依赖,当天可验)→ 验证:无公网 IP 的节点可被平台访问。
- 身份:每节点独立凭据 + 吊销(替换共享 bearer)→ 验证:吊销单台后该台拨入被拒,其余不受影响。
- 强约束落码:实例所属 == 客户端主人;共享密钥不下发客户端(红线级)→ 验证:断言/测试钉住,构造越权用例必须失败。
- 分发与自动升级 + 客户端 × 平台版本兼容矩阵 → 验证:旧客户端连新平台给出可读的「需升级」而非崩。
六、验收
| # | 口径 | 期望 |
|---|---|---|
| A | 可行性判定 | 已给出(✅ 可行 + 80% 形状 + 缺口 4 条)—— 本档已交付 |
| B | 形态可选性 | 三档各有优缺、含倾向(B),且已按用户口径收窄为单机自用 |
| C | 落地可执行性 | 6 步,每步可单独回滚,且第 1 步不依赖服务器 |
| D | 未验证项透明 | §五 五条未验证项已列全(Windows/macOS 起实例、soft 实际隔离强度、共享密钥能否按形态裁剪、打洞替换代价、版本矩阵判据) |
七、回滚
- 本档自身:零改动 ⇒ 无回滚需要。
- 若按 §五 执行:全程只新增(新客户端形态 + 新 Spawner 实现),服务端现有路径不动 ⇒ 删客户端即回到现状。
- 服务器侧待复核事实(非本档动作):控制面机规格(1.8 GB / 2 核 是 09-08 旧记录);47↔106 跨云实测 ~22 KB/s。
八、回报格式
执行会话回填:① 每一步的验证命令 + 实际输出 ② 触及的文件清单(应与 §三 一致,多出来的要说明)③ 红线遵守声明(R2 官方包零改动 / R5 未下发平台凭据)④ commit ⑤ 未完成项与卡点(附客观依据)⑥ 若推翻本档任一结论,给出取证。
九、本档需收口的两处(未处理,仅报告)
- 双源声明:
dsh客户端化部署方案_20260916.md(v3)自称「'客户端化'的单一来源」,而dsh桌面客户端_开发方案_20260916.md(v1)与其同日并存且不同层(平台侧 vs 交付载体层)⇒ 属「第二个漂移源」风险。建议:v3 定平台侧、v1 定交付层,v3 补一行指针指向 v1。 - 判定句互相矛盾:v3 §12 附录 C 把「官方桌面版(Electron)作为载体」列为放弃项,而 v1 恰恰选了这条路(且其「保留壳、换内核」已实际消解该理由)⇒ 并列阅读会读成"同一件事既放弃又采纳"。建议在 v3 §12 该行加注「已被 v1 以'换内核'方式规避,判定失效」。
⚠️ 这两处不在本档 lane(两份文档已收口、只读),仅报告不代改。
附录 A · 原始规划正文(逐字保留 · 2026-09-16)
以下为工作区根
可行性评估_客户端安装与覆盖网络互联_20260916.md的原文全文,仅删除其一级标题(避免与档案标题重复), 其余一字未改;本档的可判定部分以上方 8 段为准。
日期:2026-09-16 | 状态:调研稿(只读取证完成,未改任何代码/服务器) 触发:用户问「当前项目是否可以改造为支持服务部署以及客户端安装(客户端壳套服务器项目),让他们通过覆盖网络互联」 ⚠️ 本稿落点说明:文档库(
dsh-server-docs/)当时被全局执行锁占用(持有者guest迁移-2307,09-15 23:08 起)⇒ 按纪律未写入文档库,暂落工作区根。锁释放后应转为04-调整方案/<NN>-*.md正式档案并登记。
TL;DR
可行,而且现有架构已经给出约 80% 的形状 —— 因为「一台机器 = 一个可被平台拨入的执行体」这件事,T08 集群化已经定义完了,并且已经有两条现成能力正好解决"没有公网 IP":
① soft 隔离模式下实例只是一个普通子进程(不需要 root / bwrap / systemd);
② Worker 用拨出式 SSH 反向隧道接入 Manager —— 节点本来就不需要公网 IP。
真正的缺口是 4 条:客户端运行时落点、节点身份(现为共享令牌)、信任模型反转、分发与版本矩阵。
一、现成资产(可直接复用 · 均带代码坐标,已核实)
| # | 资产 | 证据 | 为什么关键 |
|---|---|---|---|
| 1 | soft 隔离模式:实例 = 裸子进程 |
src/supervisor/orchestrator.ts:663 —— isolationMode !== 'account' 时直接 spawn(command, args),无 bwrap / 无 setpriv / 无 systemd-run / 不需要 root;src/config.ts:14,180('soft'|'account',默认 soft) |
客户端侧不需要任何特权即可承载实例;Linux 隔离层(bwrap·scope·uid)是可选增强,不是前置依赖 |
| 2 | Worker agent 协议(≈ 现成的"节点契约") | src/worker/agent.ts 头部 4 条纪律:单向拨入(不反向连 Manager、不写控制面)· 幂等键 operationId · 最小接口白名单 · self-fencing(epoch 落后即自停);端点:/healthz /launch /stop /status /endpoint /fence /watchdog /fs/* |
「个人电脑作为节点」所需的核心语义已经定义并跑通过(S0–S7 全绿 + 真跨机演练) |
| 3 | 拨出式反向隧道(解决无公网 IP) | src/worker/tunnel.ts:152 —— ssh -O forward -R <port>:127.0.0.1:<port>;含 20 s 本地定时器自愈(T08 §16.5 ②) |
节点主动拨出即可被平台访问,无需公网 IP、无需端口映射 —— 这正是覆盖网络"中继支"的等价物 |
| 4 | 归属/租约分层判据 | 集群化设计 §1.3:归属与租约只有 Manager 能写;Worker 自有本地库 | 客户端天生只能是数据面,不会出现"客户端写权威状态"的脑裂 —— 与"个人电脑不可信"天然相容 |
| 5 | Spawner 接口已抽象 | src/supervisor/spawner.ts(launch / stop / list)+ local-* / remote-* 两个实现 |
新增一种"客户端节点"= 多一个 Spawner 实现,不是改内核 |
| 6 | 平台无跨平台分支 | 全仓仅 src/supervisor/firewall.ts:42 一处 process.platform === 'linux'(且仅用于 nft 联网护栏) |
除隔离与防火墙外,代码本身跨平台 |
结论:能移植的不是"平台",而是实例运行时 + 节点代理这两块;管理面(门户/DB/归属/租约)留在服务器不动。
二、缺口(4 条,按必须先解决排序)
缺口 1 · 客户端运行时落点(技术,自决范围)
- Linux 侧原语分布(已清点):
bwrap(orchestrator.ts/spawner.ts/agent.ts/cli.ts/routes/admin.ts)·systemd-run(cli.ts/orchestrator.ts)·setpriv(cli.ts/config.ts/orchestrator.ts/routes/business-plugins.ts)·nft(cli.ts/config.ts/orchestrator.ts/agent.ts)· 绝对路径/var/lib/dshs/opt/dshs/usr/local/dsh-runtime。 - ⇒ 客户端侧需要一套平台无关的落点:Node +
dsh可执行 + profile + 工作区目录(Windows 用%LOCALAPPDATA%、macOS 用~/Library/Application Support)。 - ⚠️ 未验证(须实测):
dsh自身在 Windows / macOS 上的沙箱后端行为。Linux 侧注释显示 dsh 有"沙箱后端探针",探针失败会refusing to run the command unconfined(实例内 bash 被整体拒绝)—— Windows / macOS 上走哪条后端、是否可用,尚无证据。 (验收口径 L2 起:客户端上起一个实例 →curl实例页 200 + 实例内跑一次 bash 工具。)
缺口 2 · 节点身份(现在是共享令牌,公网上不成立)
- 现状自陈(
agent.ts头部):token 是共享密钥 + bearer 式比较,"仅内网 + nft 白名单";HMAC / 防重放留待后续。 - 个人电脑在公网 ⇒ 共享令牌无法吊销单个节点、无法抗重放、一台泄露等于放行全部。
- ⇒ 必须升级为每节点独立身份(客户端证书 / 独立密钥对)+ 准入与吊销,且通道本身要端到端加密。
缺口 3 · 信任模型反转(最重要的一条,不是技术问题而是边界问题)
- 现平台假设:宿主机由我们掌控(所以用 uid 隔离"用户 A 防用户 B")。
- 客户端形态下:宿主机由用户掌控 ⇒ 原有隔离语义在"防机器主人"这一维上直接失效(机器主人本来就能读自己机器上的一切)。
- ⇒ 必须新增硬约束:一台客户端上的实例只能属于该客户端的主人;平台不得把别人的实例、别人的数据、或平台级凭据下发到客户端。
- ⚠️ 现状反例:平台会把共享模型密钥注入实例(档案 85/87 的两层密钥中的"共享"那一层)—— 下发到用户掌控的机器等于把平台密钥交给用户。
- ⇒ 客户端形态必须只用"用户自己的密钥"这一层;共享层只在服务端实例上使用。
缺口 4 · 分发与版本矩阵(运维)
- 客户端安装包 + 自动升级 + 客户端版本 × 平台版本兼容矩阵(现有
plugin-compat/dsh-install.ts是同类问题的服务端解,需要客户端版对应物)。 - 客户端一多,故障面从"我们的机器"扩到"用户的机器"(系统时间、磁盘、杀软、代理),排障成本上升。
三、形态三档(真取舍,需用户拍板)
判据:三档的最终效果对用户完全不同(数据在哪、算力归谁、谁能调度),属"业务目标与优先级",不能由技术标准裁决。
A 档 · 客户端只做"壳"(远程访问)
- 优点:改动最小;安全模型零变化;不引入任何跨租户风险;沿用现有实例与全部隔离。
- 缺点:个人电脑不成为节点,算力仍在服务器;离线不可用;覆盖网络在这一档没有实际用途。
B 档 · 客户端自带"自己的实例"(平台退化为控制面 + 中继 + 目录)
- 优点:数据与算力都在用户自己机器上,服务器成本大降;离线可用;能用到本机文件与本地软件;不引入跨租户风险(每位用户只碰自己的机器)。
- 缺点:
soft模式隔离强度低于现在的account模式(本机场景可接受,但需明确边界);Windows / macOS 运行时未验证;平台对实例的可控性下降(升级、清理、取证都要客户端配合)。
C 档 · 客户端作为集群 Worker(平台可把实例调度到用户机器)
- 优点:算力可横向扩张且复用已跑通的集群协议(agent 四纪律 + 归属/租约分层已就位);对平台运营方收益最直接。
- 缺点:信任模型反转(别人的代码、别人的数据、平台凭据落到用户掌控的机器上);必须有节点准入 + 吊销 + 强身份;合规与责任边界要重新界定;Windows / macOS 的隔离层基本要从零做(无 bwrap / 无 systemd / 无 uid 隔离)。
我的倾向:先做 B(唯一一档能"增量落地 + 不引入跨租户风险",且正好吃满资产 1/3/4 的现成能力)。A 档价值有限(覆盖网络用不上);C 档应等服务端能力与合规边界都清楚后再谈。
四、若走 B 档:落地顺序(每步可单独回滚)
- 验证 dsh 在 Windows / macOS 的可运行性(只读 + 本地装,不动服务器)——产出:能否起实例 + 实例内 bash 工具是否可用(L2/L4)。
- 客户端节点代理(复用 agent 协议,落
soft模式):先只做/healthz+/launch+/stop+/fence,台账式幂等。 - 通道:先用现有拨出式 SSH 反向隧道打通(零新依赖,当天可验),再评估换"打洞优先 + 中继兜底"。
- 身份:每节点独立凭据 + 吊销(替换共享 bearer)。
- 强约束落码:实例所属 == 客户端主人;共享密钥不下发客户端(红线级,须有断言/测试钉住)。
- 分发与自动升级。
回滚:全程只新增(新客户端形态 + 新 Spawner 实现),服务端现有路径不动 ⇒ 删客户端即回到现状。
五、未验证 / 待确认(诚实清单,勿当已知)
| # | 项 | 状态 |
|---|---|---|
| 1 | dsh 在 Windows / macOS 起实例 + 实例内 bash 是否可用 |
⚠️ 未验证(本轮无对应环境) |
| 2 | soft 模式下实例的实际隔离强度(能读到宿主什么) |
⚠️ 未验证(本轮只读了代码分支,未实测) |
| 3 | 客户端形态下"共享密钥不下发"是否已有现成开关 | ⚠️ 待查(档案 85/87 是两层密钥,需确认能否按形态裁剪) |
| 4 | 打洞优先方案与现有隧道的替换代价 | 📋 方案调研(见同日讨论结论:自托管 NetBird / headscale + 自建中继) |
| 5 | 客户端 × 平台版本兼容矩阵的判据 | 📋 待设计(可仿 plugin-compat) |
附:本轮取证命令(可复跑)
cd /d/github/dsh_shenxian
sed -n '660,665p' src/supervisor/orchestrator.ts # soft 模式 = 裸 spawn
grep -n "isolationMode" src/config.ts # 'soft'|'account',默认 soft
sed -n '1,30p' src/worker/agent.ts # 节点四条协议纪律
sed -n '147,155p' src/worker/tunnel.ts # -R 反向转发(拨出式)
grep -rn "process.platform" src # 全仓仅 1 处(firewall.ts)
六、与另两份客户端文档对账(2026-09-16 08:5x 追加)
对账对象(同为大工作区根,均晚于本稿 8 小时,08:06 产出):
dsh客户端化部署方案_20260916.md(v3 · 单机自用 · 自称「客户端化」的单一来源)dsh桌面客户端_开发方案_20260916.md(v1 · 基于官方 Electron 壳 · 独立仓库)
6.1 结论:不冲突,是互补;但两处需要收口
| 维度 | 本稿 | 部署方案 v3 | 桌面客户端 v1 | 判定 |
|---|---|---|---|---|
| 形态选择 | 三档 A/B/C,倾向 B | 单机自用(用户原话已定,§12) | 单机自用为默认,域名可切多人 | ✅ 同向(本稿的 B 即其单机自用;三档问题已被用户拍板,见 6.2) |
| 地基 | 资产 1:soft 默认、无需 root |
明确"隔离档保持默认 soft" | 同 | ✅ 互相印证 |
| 平台改动面 | 资产 6:仅 firewall 一处平台分支 | "唯一硬阻塞 = spawn 方式" | P1 同一条 | ✅ 不同维度,可并存 |
| 分发与版本 | 缺口 4 | — | §3.4 上游同步 / §4.6 自动更新 / §6 打包 | ✅ 已被其覆盖 |
6.2 本稿需修正的两点(如实记录,勿当原判)
- 缺口 1 的位置标错了:本稿把"客户端运行时"列为缺口、并怀疑
dsh在 Windows 的沙箱后端不可用。部署方案 v3 已在本机 Windows 实测:真正的硬阻塞是平台自己的启动方式 —— 裸名spawn('npm')在 Windows 报ENOENT(全局包是.cmd),显式.cmd被 Node 拒(EINVAL),改用cmd.exe /c或shell: true即通。⇒ 阻塞点在平台调用层,不在 dsh 运行时,且代价很小(一处调用方式)。 - 三档"需用户拍板"已不再是开放问题:用户此前已定「考虑用户自己使用就可以了,不用考虑当作服务器 其他人访问」⇒ A/C 两档的多人维度已被放弃。本稿第五节的三档保留为历史决策依据,不再是待拍板项。
6.3 仅本稿覆盖、另两份未涉的:覆盖网络(用户最初问题里的那一项)
- 两份文档的"多人形态"路线 = 内网 DNS 泛解析 + 域名(局域网内多机访问),与"覆盖网络"是同一需求的两种替代实现:
- 局域网 + 域名:只能在同一内网;跨公网不行;需要域名与 DNS 泛解析。
- 覆盖网络:跨公网可直连(打洞优先、中继兜底);不需要域名;但需要客户端常驻 + 节点身份。
- ⇒ 本稿与另两份文档在"能力面"上不冲突,但在"要不要跨公网互连"上是分叉;两份文档默认不跨公网。若确定不做跨公网,本稿的缺口 2/3 可整体降级为"不适用"。
- 📄 百台规模的逻辑预演见
覆盖网络_百台规模推演_20260916.md(2026-09-16):结论 = 100 台规模下控制面不是瓶颈,中继带宽与"大流量过网"才是(实例首屏含 ≈10.8 MB 客户端脚本);而"单机自用"天然把大流量留在回环上 ⇒ 该形态在 100 台规模下是正确版而非妥协版。
6.4 两处需收口的隐患(建议进文档库时一并处理)
- 双源声明:部署方案 v3 自称「'客户端化'的单一来源」,而桌面客户端 v1 与其同日并存且内容不同层(平台侧 vs 交付载体层)⇒ 属项目明令禁止的"第二个漂移源"风险。建议:v3 定平台侧、v1 定交付层,v3 里补一行指针指向 v1,或合并。
- 判定句互相矛盾:v3 §12 附录 C 把「官方桌面版(Electron)作为载体」列为放弃项(理由:换载体会丢掉门户能力),而 v1 恰恰选了这条路。v1 的"保留壳、换内核为我们的平台"已实际消解该理由(门户能力并未丢),但 v3 的判定句未更新 ⇒ 并列阅读时会读成"同一件事既放弃又采纳"。建议在 v3 §12 该行加注"已被 v1 以'换内核'方式规避,判定失效"。
6.5 本稿的缺口 3 仍然有效,且是"切多人形态时的前置门禁"
- 部署方案 v3 §1.3 明确写:切多人形态零代码(只配域名),且多人时隔离档仍是
soft⇒ 用户之间无隔离;桌面客户端 v1 §4.7 进一步要求"客户端 spawn 平台时不要清理环境变量、不要白名单化"(为透传域名)。 - 这两条与本稿缺口 3 的硬约束正面相交:
- ① 实例只能属于机器主人 —— 单机自用下天然成立;一旦配域名多人用,立刻不成立(soft 档无隔离)。
- ② 平台级共享模型密钥不得随客户端分发 —— 与"环境变量原样继承"相冲。建议改为白名单透传,只放形态开关三项(
DSHS_BASE_DOMAIN/DSHS_COOKIE_DOMAIN/DSHS_SECURE_COOKIES),模型密钥只走"用户自己的密钥"那一层。
- ⇒ 结论:不是"不兼容",而是"范围收窄把风险面暂时关掉了、但开关就在配置里"。建议把上述两条写成切多人形态的前置检查项(而非留在散文里)。