dsh-multiuser — 多用户模式插件
让一台主机上的多个用户都能访问 DeepSeek Harness Web,登录后工作台=各自的 home 目录, 同时共享统一内置的插件与 skills,每个用户还能定制自己的插件/skills/模型/key。
一切路径与开关可配置,并在「设置 → 插件配置」页有表单,保存即时生效。
两级开关
| 级别 | 操作 | 效果 |
|---|---|---|
| 插件级 | 市场/插件列表停用本插件(disabled: true)或 dsh plugin remove |
多用户能力完全消失 |
| 模式级 | 设置 → 插件配置 → dsh-multiuser → enabled: false |
插件在但多用户模式关闭(状态路由返回 enabled:false,托管操作 403) |
架构
┌─ base 层(统一内置,管理员维护,普通用户只读)──────────────┐
│ <base>/plugins/package.json+node_modules 共享插件树 │
│ <base>/skills/ 共享技能库 │
│ <base>/cordis.base.yml base 配置行 │
└──────────────────────────────────────────────────────────────┘
┌─ custom 层(每用户,自己的 ~/.dsh)─────────────────────────┐
│ profiles/web/node_modules → 符号链接 base 插件树(只读) │
│ profiles/web/package.json bundles = base + 用户自定义 │
│ profiles/web/cordis.patch.yml base 行 + 用户自己的行 │
│ profiles/node_modules/ 用户自装插件包(兜底解析目录) │
│ custom/bundles.json 用户自定义 bundles 清单 │
│ ~/.dsh/skills 用户技能(自动发现) │
│ settings.yaml / .credentials.yaml 模型与 API key │
└──────────────────────────────────────────────────────────────┘
每用户一个 dsh web 实例(127.0.0.1:<port>),门户(niginx)登录后按用户名路由。
目录结构
dsh-multiuser/
package.json # dsh.bundle.patch 声明,可被市场/dsh plugin 安装
cordis.patch.yml # 插件行
lib/
index.js # apply():挂设置 + 挂路由
settings.js # 配置 schema(设置页表单)
prepare.js # 每用户 profile 准备(bundles/符号链接/cordis/模板)
instances.js # 子实例 spawn/stop/list(detached 进程组)
routes.js # /dsh-multiuser/* HTTP API(loopback 同源守卫)
bin/bootstrap-base.sh # 管理员:从现有 profile 建 base 层
test/prepare.test.mjs # 本地分层引擎测试(node test/prepare.test.mjs)
安装
把本目录作为插件源安装进 web profile(三选一):
# 1) 本地目录(开发/试点最快)
dsh plugin --profile web add /path/to/dsh-multiuser
# 2) 本地 tarball
dsh plugin --profile web add file:dsh-multiuser-0.1.0.tgz
# 3) 市场:先在市场注册 git/file 源,再一键安装
装完重启 dsh web。然后到「设置 → 插件配置 → dsh-multiuser」确认配置, 「插件列表」里可整体停用/启用本插件。
配置项
| 字段 | 默认 | 说明 |
|---|---|---|
enabled |
true | 模式级开关 |
baseDir |
/srv/dsh/base | base 根目录 |
basePlugins |
/srv/dsh/base/plugins | 共享插件树(package.json + node_modules) |
baseSkills |
/srv/dsh/base/skills | 共享技能库 |
basePatch |
/srv/dsh/base/cordis.base.yml | base 配置行(合并进每用户 cordis.patch.yml) |
baseBundles |
auto | auto=读 basePlugins/package.json;或 JSON 数组 |
customHome |
{{user.home}}/.dsh |
每用户 DSH_HOME |
customPlugins |
{{user.home}}/.dsh/profiles/node_modules |
用户自装插件目录 |
customSkills |
{{user.home}}/.dsh/skills |
用户技能目录 |
customBundlesFile |
{{user.home}}/.dsh/custom/bundles.json |
用户 bundles 清单 |
workspace |
{{user.home}} |
每用户工作台(实例 cwd) |
portStart |
3081 | 端口分配起点(按用户名排序) |
trustedHosts |
[dsh.example.com:443] | 门户 Host,传给子实例 --trusted-host(放行 browser-trust 围栏) |
extraArgs |
[] | 追加 dsh 参数 |
runAs |
current | current=当前用户;system=su 到目标用户(需 root) |
idleStopMinutes |
0 | 空闲回收(0=常驻) |
usersEnabled |
[] | 白名单;空=全部(减去 exclude) |
usersExclude |
[系统账号…] | 排除名单 |
settingsTemplateYaml |
'' | 新用户 settings.yaml 首启模板(如预置 uniapi 供应商) |
路径支持 {{user.name}} / {{user.home}} 模板。
部署
1. 管理员建 base 层(root)
sudo ./bin/bootstrap-base.sh ~/.dsh/profiles/web /srv/dsh/base --copy
2. 共享运行时(root,可选但推荐)
node/pnpm/dsh 需所有用户可执行:把 wukuncan 的 nvm 部署到共享路径,
或另装系统 node ≥22 后:npm i -g pnpm 和 npm i -g @deepseek-ai/dsh。
3. 门户(nginx)
子实例只绑 127.0.0.1。门户做登录 + 按用户名路由到对应端口。
映射表由插件写入 <baseDir>/instances.json({ports: {alice: 3081, ...}}),
门户可用它生成 nginx map $remote_user $backend(见 deploy/nginx-portal.conf.example)。
登录推荐 PAM 校验系统账号(nginx auth_request + 小校验端点),
或 htpasswd(需维护口令)。HTTPS 用内部 CA/mkcert。
runAs: system 时,需保证插件进程能以 su - <user> 拉起实例(root 部署)。
4. 试点(本容器无 root 时)
# 设置里: runAs=current, baseDir/basePlugins 指向工作区内的 base(--link 模式建的)
# 然后: curl http://127.0.0.1:3080/dsh-multiuser/status 应返回 enabled:true
# 启动 alice: curl -X POST http://127.0.0.1:3080/dsh-multiuser/start -d '{"user":"alice"}'
用户定制插件
- 把包装进用户的
customPlugins目录(默认~/.dsh/profiles/node_modules, Node 解析兜底目录):# 在用户的 ~/.dsh/profiles 下建最小 package.json 后 pnpm --dir ~/.dsh/profiles add <你的插件包> - 在
~/.dsh/custom/bundles.json登记包名(数组)。 - 下次该用户实例启动时,bundles = base + 自己的,即生效。
普通用户的「一键市场安装」默认不做(会写共享树);装包统一走上面的个人目录, 共享树只有管理员动。
HTTP API(loopback 同源)
GET /dsh-multiuser/status 开关、用户、端口、实例
GET /dsh-multiuser/config 当前生效配置
POST /dsh-multiuser/prepare {"user":"alice"}
POST /dsh-multiuser/start {"user":"alice"}
POST /dsh-multiuser/stop {"user":"alice","force":false}
POST /dsh-multiuser/stop-all
限制与风险
- 无 root 时只能
runAs: current(实例以插件进程的 OS 用户运行,隔离靠 DSH_HOME/工作台路径); 真正的 OS 用户隔离需要 root 部署 +runAs: system。 - 门户认证是唯一防线(DSH 无应用内登录),务必上 HTTPS。
- base 层并发写冲突:普通用户只读,安装/升级由管理员在维护窗口统一做。
- 每个子实例是独立 dsh web 进程(数百 MB 内存级),建议
idleStopMinutes设非 0 或门户按需拉起。
No comments yet. Be the first to write one.