Files
dsh_shenxian/dsh-server-docs/04-调整方案/103-客户端安装与覆盖网络互联-可行性评估.md
T
admin 4e3a1a4a13 docs(overlay): 覆盖网络/客户端化 10 份规划转正式档案 103-112 + 登记
- 新增 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> 再写)
2026-09-16 10:25:09 +08:00

23 KiB
Raw Blame History

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)。

四、决策点

已定

  1. 形态已拍板 = 单机自用(用户原话:「考虑用户自己使用就可以了,不用考虑当作服务器 其他人访问」)⇒ 本档 §三 的 A/C 两档「多人维度」已放弃,三档表保留为历史决策依据,不再是待拍板项。
  2. 地基 = soft 隔离档(用户已定:「隔离档保持默认 soft」)—— 三份客户端文档同向。

历史决策依据(本档 §三,已不再是开放问题):A 只做壳(覆盖网络用不上)|B 自带实例(本档倾向)|C 客户端当集群 Worker(需强身份 + 重划合规边界)。

待执行会话复核(非上抛项):soft 模式在 Windows / macOS 上的实际隔离强度与可运行性 —— 本档已实测修正:真正的硬阻塞不在 dsh 运行时,而在平台自己的启动方式(裸名 spawn('npm') 在 Windows 报 ENOENT;显式 .cmd 被 Node 拒 EINVAL;改 cmd.exe /c 或 shell: true 即通)⇒ 代价 = 一处调用方式。

五、步骤(若走 B 档;每步自带一次验证)

  1. 验证 dsh 在 Windows / macOS 可运行性(只读 + 本地装,不动服务器)→ 验证:客户端能起实例 + 实例内 bash 工具可用。
  2. 客户端节点代理(复用 agent 协议、落 soft)—— 先只做 /healthz /launch /stop /fence → 验证:台账式幂等(同 operationId 重放不产生副作用)。
  3. 通道:先用现有拨出式 SSH 反向隧道打通(零新依赖,当天可验)→ 验证:无公网 IP 的节点可被平台访问。
  4. 身份:每节点独立凭据 + 吊销(替换共享 bearer)→ 验证:吊销单台后该台拨入被拒,其余不受影响。
  5. 强约束落码:实例所属 == 客户端主人;共享密钥不下发客户端(红线级)→ 验证:断言/测试钉住,构造越权用例必须失败。
  6. 分发与自动升级 + 客户端 × 平台版本兼容矩阵 → 验证:旧客户端连新平台给出可读的「需升级」而非崩。

六、验收

# 口径 期望
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 ⑤ 未完成项与卡点(附客观依据)⑥ 若推翻本档任一结论,给出取证。

九、本档需收口的两处(未处理,仅报告)

  1. 双源声明:dsh客户端化部署方案_20260916.md(v3)自称「'客户端化'的单一来源」,而 dsh桌面客户端_开发方案_20260916.md(v1)与其同日并存且不同层(平台侧 vs 交付载体层)⇒ 属「第二个漂移源」风险。建议:v3 定平台侧、v1 定交付层,v3 补一行指针指向 v1。
  2. 判定句互相矛盾: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 档:落地顺序(每步可单独回滚)

  1. 验证 dsh 在 Windows / macOS 的可运行性(只读 + 本地装,不动服务器)——产出:能否起实例 + 实例内 bash 工具是否可用(L2/L4)。
  2. 客户端节点代理(复用 agent 协议,落 soft 模式):先只做 /healthz + /launch + /stop + /fence,台账式幂等。
  3. 通道:先用现有拨出式 SSH 反向隧道打通(零新依赖,当天可验),再评估换"打洞优先 + 中继兜底"。
  4. 身份:每节点独立凭据 + 吊销(替换共享 bearer)。
  5. 强约束落码:实例所属 == 客户端主人;共享密钥不下发客户端(红线级,须有断言/测试钉住)。
  6. 分发与自动升级。

回滚:全程只新增(新客户端形态 + 新 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. 缺口 1 的位置标错了:本稿把"客户端运行时"列为缺口、并怀疑 dsh 在 Windows 的沙箱后端不可用。部署方案 v3 已在本机 Windows 实测:真正的硬阻塞是平台自己的启动方式 —— 裸名 spawn('npm') 在 Windows 报 ENOENT(全局包是 .cmd),显式 .cmd 被 Node 拒(EINVAL),改用 cmd.exe /c 或 shell: true 即通。⇒ 阻塞点在平台调用层,不在 dsh 运行时,且代价很小(一处调用方式)。
  2. 三档"需用户拍板"已不再是开放问题:用户此前已定「考虑用户自己使用就可以了,不用考虑当作服务器 其他人访问」⇒ A/C 两档的多人维度已被放弃。本稿第五节的三档保留为历史决策依据,不再是待拍板项。

6.3 仅本稿覆盖、另两份未涉的:覆盖网络(用户最初问题里的那一项)

  • 两份文档的"多人形态"路线 = 内网 DNS 泛解析 + 域名(局域网内多机访问),与"覆盖网络"是同一需求的两种替代实现:
    • 局域网 + 域名:只能在同一内网;跨公网不行;需要域名与 DNS 泛解析。
    • 覆盖网络:跨公网可直连(打洞优先、中继兜底);不需要域名;但需要客户端常驻 + 节点身份。
  • ⇒ 本稿与另两份文档在"能力面"上不冲突,但在"要不要跨公网互连"上是分叉;两份文档默认不跨公网。若确定不做跨公网,本稿的缺口 2/3 可整体降级为"不适用"。
  • 📄 百台规模的逻辑预演见 覆盖网络_百台规模推演_20260916.md(2026-09-16):结论 = 100 台规模下控制面不是瓶颈,中继带宽与"大流量过网"才是(实例首屏含 ≈10.8 MB 客户端脚本);而"单机自用"天然把大流量留在回环上 ⇒ 该形态在 100 台规模下是正确版而非妥协版。

6.4 两处需收口的隐患(建议进文档库时一并处理)

  1. 双源声明:部署方案 v3 自称「'客户端化'的单一来源」,而桌面客户端 v1 与其同日并存且内容不同层(平台侧 vs 交付载体层)⇒ 属项目明令禁止的"第二个漂移源"风险。建议:v3 定平台侧、v1 定交付层,v3 里补一行指针指向 v1,或合并。
  2. 判定句互相矛盾: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),模型密钥只走"用户自己的密钥"那一层。
  • ⇒ 结论:不是"不兼容",而是"范围收窄把风险面暂时关掉了、但开关就在配置里"。建议把上述两条写成切多人形态的前置检查项(而非留在散文里)。