在一台服务器上为多人分配隔离的 dsh 网页实例
34.8/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/9/18 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
自动兼容检查未通过:仓库根目录及浅层子目录均无 dsh 插件清单,无法用 dsh 插件安装命令安装。以下命令仍可尝试,但可能失败。
无法用 dsh 插件命令安装(仓库内无 dsh 插件清单)
git clone https://github.com/DreamRift/dsh-hub.git按该仓库 README 的原生方式安装;若作者另行发布了 DSH 插件包,请以其文档为准
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:需留意
是什么
dsh 原生插件 · market
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 72 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
⚠︎ 实装验证未通过(unknown · 2026/10/25) ——可能是验证环境差异,装前建议到 GitHub 仓库确认最近更新与 issue。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查需源码安装仓库根目录及浅层子目录均无 dsh 插件清单,无法用 dsh 插件安装命令安装
展开查看检查明细 ↓
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✗npm 包dsh-hub(未发布到 npm,仅可源码安装)
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖未声明 dsh 版本约束
✗入口文件缺少入口声明
源码安装时若 pnpm 拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑。
验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/11/3 23:24:15
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 59 处,展示前 55 条)
- 读取本地文件dsh-hub/spikes/s1-reverse-proxy.mjs:28
if (fromEnv && existsSync(fromEnv)) return [process.execPath, fromEnv]; - 读取本地文件dsh-hub/spikes/s1-reverse-proxy.mjs:30
if (existsSync(guess)) return [process.execPath, guess]; - 发起网络请求dsh-hub/spikes/s1-reverse-proxy.mjs:52
http.get({ host: HOST, port: PROXY_PORT, path }, (res) => { - 发起网络请求dsh-hub/spikes/s1-reverse-proxy.mjs:63
const up = http.request({ host: HOST, port: targetPort, path: req.url, method: req.method, headers: req.headers }, (r) => { - 发起网络请求dsh-hub/spikes/s1-reverse-proxy.mjs:100
const req = http.request({ - 发起网络请求dsh-hub/spikes/s1-reverse-proxy.mjs:121
const req = http.request({ - 执行外部命令来自配置/变量dsh-hub/spikes/s1-reverse-proxy.mjs:142
const child = spawn(binJs, ['web', '--host', HOST, '--port', String(DSH_PORT), '--no-open'], { - 删除本地文件递归dsh-hub/spikes/s1-reverse-proxy.mjs:189
rmSync(home, { recursive: true, force: true }); - 读取本地文件dsh-hub/spikes/s2-trusted-host.mjs:21
try { entries = readdirSync(dir, { withFileTypes: true }); } catch { return; } - 读取本地文件dsh-hub/spikes/s2-trusted-host.mjs:27
try { t = readFileSync(p, 'utf8'); } catch { continue; } - 读取本地文件dsh-hub/spikes/s2-trusted-host.mjs:36
if (existsSync(rootDir)) walk(rootDir); - 执行外部命令固定命令dsh-hub/spikes/s4-npx-version.mjs:26
const which = spawnSync('which', ['npx'], { encoding: 'utf8' }); - 执行外部命令来自配置/变量dsh-hub/spikes/s4-npx-version.mjs:59
const child = spawn(process.execPath, [npxCli, '--yes', `@deepseek-ai/dsh@${VER}`, ...args], { - 删除本地文件递归dsh-hub/spikes/s4-npx-version.mjs:108
rmSync(home, { recursive: true, force: true }); - 删除本地文件递归dsh-hub/spikes/s5-nickname-dir.mjs:49
rmSync(ROOT, { recursive: true, force: true }); - 写入本地文件dsh-hub/spikes/s5-nickname-dir.mjs:50
mkdirSync(ROOT, { recursive: true }); - 写入本地文件dsh-hub/spikes/s5-nickname-dir.mjs:56
mkdirSync(zhDir, { recursive: true }); - 写入本地文件dsh-hub/spikes/s5-nickname-dir.mjs:57
writeFileSync(join(zhDir, 'note.txt'), '中文目录测试', 'utf8'); - 读取本地文件dsh-hub/spikes/s5-nickname-dir.mjs:58
const zhStat = statSync(zhDir); - 读取本地文件dsh-hub/spikes/s5-nickname-dir.mjs:59
record('中文昵称直接作目录名(ext4 mkdir+读写)', existsSync(zhDir) && zhStat.isDirectory()); - 写入本地文件dsh-hub/spikes/s5-nickname-dir.mjs:89
renameSync(oldDir, newDir); - 读取本地文件dsh-hub/spikes/s5-nickname-dir.mjs:90
record('rename() 支持中文目录改名', existsSync(newDir) && readFileSync(join(newDir, 'note.txt'), 'utf8') === '中文目录测试'); - 读取本地文件dsh-hub/spikes/s5-nickname-dir.mjs:90
record('rename() 支持中文目录改名', existsSync(newDir) && readFileSync(join(newDir, 'note.txt'), 'utf8') === '中文目录测试'); - 写入本地文件dsh-hub/spikes/s5-nickname-dir.mjs:97
mkdirSync(restore, { recursive: true }); - 读取本地文件dsh-hub/spikes/s5-nickname-dir.mjs:99
record('tar 备份/还原保留中文目录名', tar.status === 0 && untar.status === 0 && existsSync(join(restore, '张三·改名', 'note.txt')), tar.status === 0 ? '' : `tar exit - 读取本地文件dsh-hub/spikes/s5-nickname-dir.mjs:102
const listing = readdirSync(restore); - 写入本地文件dsh-hub/spikes/s5-nickname-dir.mjs:107
for (const sub of ['home', 'workspace', 'logs']) mkdirSync(join(inst, sub), { recursive: true }); - 删除本地文件dsh-hub/spikes/s5-nickname-dir.mjs:113
try { rmSync(join(ROOT, 'backup.tar'), { force: true }); } catch {} - 读取本地文件dsh-hub/src/db.ts:22
if (!existsSync(dataDir)) mkdirSync(dataDir, { recursive: true }); - 写入本地文件dsh-hub/src/db.ts:22
if (!existsSync(dataDir)) mkdirSync(dataDir, { recursive: true }); - 写入本地文件dsh-hub/src/db.ts:24
chmodSync(dataDir, 0o700); - 写入本地文件dsh-hub/src/db.ts:27
chmodSync(dbPath, 0o600); - 读取本地文件dsh-hub/src/index.ts:25
const pkg = JSON.parse(readFileSync(join(here, '..', 'package.json'), 'utf8')) as { version?: string }; - 读取本地文件dsh-hub/src/instances.ts:27
if (!existsSync(dir)) mkdirSync(dir, { recursive: true }); - 写入本地文件dsh-hub/src/instances.ts:27
if (!existsSync(dir)) mkdirSync(dir, { recursive: true }); - 写入本地文件dsh-hub/src/instances.ts:28
chmodSync(dir, 0o700); - 写入本地文件dsh-hub/src/instances.ts:62
for (const sub of INSTANCE_SUBDIRS) mkdirSync(join(dir, sub), { recursive: true }); - 删除本地文件递归dsh-hub/src/instances.ts:68
rmSync(dir, { recursive: true, force: true }); - 删除本地文件递归dsh-hub/src/instances.ts:117
rmSync(instanceDir(dirName, record.id), { recursive: true, force: true }); - 读取本地文件dsh-hub/src/supervisor.ts:84
if (fromEnv && existsSync(fromEnv)) return fromEnv; - 读取本地文件dsh-hub/src/supervisor.ts:86
if (existsSync(guess)) return guess; - 读取本地文件dsh-hub/src/supervisor.ts:120
const cmdline = readFileSync(`/proc/${pid}/cmdline`, 'utf8').replace(/ /g, ' '); - 写入本地文件dsh-hub/src/supervisor.ts:131
mkdirSync(p, { recursive: true }); - 写入本地文件dsh-hub/src/supervisor.ts:155
writeFileSync(fd, token); - 读取本地文件dsh-hub/src/supervisor.ts:171
if (readFileSync(path, 'utf8').trim() !== token) return; - 删除本地文件dsh-hub/src/supervisor.ts:176
try { rmSync(path, { force: true }); } catch { } - 写入本地文件dsh-hub/src/supervisor.ts:180
writeFileSync(instancePidfile(record), String(pid)); - 删除本地文件dsh-hub/src/supervisor.ts:184
try { rmSync(instancePidfile(record), { force: true }); } catch { } - 读取本地文件dsh-hub/src/supervisor.ts:189
const n = Number(readFileSync(instancePidfile(record), 'utf8').trim()); - 写入本地文件dsh-hub/src/supervisor.ts:199
writeFileSync(join(logDir, `start-fail-${ts}.md`), `# 启动失败快照\n\n- 实例: ${record.id}\n- 时间: ${new Date().toISOString()}\n- 原因: ${title}\n\n\`\`\`\n${det - 读取本地文件dsh-hub/src/supervisor.ts:205
if (!existsSync(logPath) || statSync(logPath).size <= maxBytes) return; - 删除本地文件dsh-hub/src/supervisor.ts:208
rmSync(bak2, { force: true }); - 写入本地文件dsh-hub/src/supervisor.ts:209
if (existsSync(bak1)) renameSync(bak1, bak2); - 写入本地文件dsh-hub/src/supervisor.ts:210
renameSync(logPath, bak1); - 执行外部命令来自配置/变量dsh-hub/src/supervisor.ts:277
child = spawn(spawnBin, spawnArgs, {
扫描于 2026/11/3(0 天前) · 范围 全包扫描 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 单机多租户实例隔离
- 实例认证与生命周期管理
- 配额与审计
README
由 DeepSeek 最新模型翻译生成DSH Hub · DeepSeek Harness 多租户多实例管理器
在单台 Linux 服务器上为多人提供各自独立的 DeepSeek Harness(dsh web)浏览器实例:网页登录、按用户隔离的昵称目录、实例生命周期(创建/启停/重启/删除/日志/孤儿回收)、管理员后台(用户管理/封禁/配额/版本白名单/审计)。
- 技术栈:Node.js ≥ 24(原生 TypeScript 运行 + 内置 node:sqlite),运行时零依赖
- 当前状态:M0–M2.1 完成(调研/脚手架/认证/生命周期/安全修复);M3 鉴权网关进行中
仓库结构
docs/ 调研笔记 / 开发计划 / Spike 验证记录 / 进展日志 dsh-hub/ 控制面实现(TypeScript 源码 + 冒烟测试 + Spike 脚本)
核心能力
| 能力 | 说明 |
| 认证 | 首启向导建管理员;注册开关;session cookie(HttpOnly + SameSite=Lax + 滑动 7 天/绝对 30 天)+ Bearer API token 双轨;写操作 CSRF;登录限速(IP+昵称) |
| 角色 | root(管管理员)/ admin(管用户与实例)/ user(仅自己资源);越权一律 403/404 |
展开完整文档(README 剩余 1 节)
DSH Hub · DeepSeek Harness 多租户多实例管理器 在单台 Linux 服务器上为多人提供各自独立的 DeepSeek Harness(dsh web)浏览器实例:网页登录、按用户隔离的昵称目录、实例生命周期(创建/启停/重启/删除/日志/孤儿回收)、管理员后台(用户管理/封禁/配额/版本白名单/审计)。 - 技术栈:Node.js ≥ 24(原生 TypeScript 运行 + 内置 node:sqlite),运行时零依赖 - 当前状态:M0–M2.1 完成(调研/脚手架/认证/生命周期/安全修复);M3 鉴权网关进行中 仓库结构 docs/ 调研笔记 / 开发计划 / Spike 验证记录 / 进展日志 dsh-hub/ 控制面实现(TypeScript 源码 + 冒烟测试 + Spike 脚本) 核心能力 | 能力 | 说明 | | 认证 | 首启向导建管理员;注册开关;session cookie(HttpOnly + SameSite=Lax + 滑动 7 天/绝对 30 天)+ Bearer API token 双轨;写操作 CSRF;登录限速(IP+昵称) | | 角色 | root(管管理员)/ admin(管用户与实例)/ user(仅自己资源);越权一律 403/404 | | 实例 | 每实例独立 DSH_HOME + 端口(4000–4999)+ workspace;spawn dsh web 独立进程组;TCP 探活(180s)+ 失败快照 + 日志轮转;重启后孤儿认领 | | 配额 | max_instances / max_running 事务化检查(BEGIN IMMEDIATE,并发不超配) | | 安全 | 封禁即停实例 + 吊销会话与 token;版本白名单(仅显式 semver);进程身份校验防 pid 复用误杀;per-instance 并发互斥 | | 审计 | 登录/建号/凭据/实例全动作入 audit_logs | 快速开始 cd dsh-hub npm install # 仅 devDependencies(typescript/@types/node);运行时零依赖 npm run dev # 监听 127.0.0.1:3082 浏览器打开 http://127.0.0.1:3082 → POST /api/auth/setup 建首个管理员(无用户时可用) 环境变量(src/config.ts 集中定义):DSH_HUB_DATA(数据根)、DSH_HUB_HOST、DSH_HUB_PORT、 DSH_HUB_COOKIE_SECURE=1(置于 Caddy/HTTPS 后启用)、DSH_BIN、DSH_HUB_DOMAIN(trusted-host 子域后缀)、DSH_HUB_TRUST_PROXY=1。 测试 cd dsh-hub bash scripts/m1-smoke.sh # 24 项:认证/角色/CSRF/限速/审计(自带启动 hub) bash scripts/m2-smoke.sh # 29 项:实例生命周期(真实 dsh web 实例) bash scripts/security-regression.sh # 38 项:攻击剧本回归(封禁链路/版本注入/并发/崩溃同步) npx tsc -p . --noEmit # 类型检查 文档 - docs/01-调研笔记.md:DSH 本体事实与借鉴项目调研 - docs/02-开发计划.md:架构、API 草案、里程碑 M0–M6、风险表 - docs/03-Spike验证记录.md:S1–S5 技术验证结论(WS 隧道/trusted-host 精确匹配等) - docs/00-进展日志.md:滚动工作状态与断点 路线图 - M3 鉴权网关:子域路由 + 所有权校验 + WS 隧道(/api/events.mux|host)+ 未运行引导页 - M4 管理员后台 UI(React + DSH 设计令牌) - M5 加固:systemd-run 限额、per-user 账号严格模式、凭据模板、备份文档 - M6 多用户压测与故障注入、部署手册 许可 个人学习项目,公开分享;使用前请自行评估安全与合规风险。
预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
DreamRift/dsh-hub
在一台服务器上为多人分配隔离的 dsh 网页实例
相关插件 · 市场 / 管理
插件精选列表awesome-dsh-plugin/awesome-dsh-plugin
DeepSeek Harness(dsh)插件精选列表
★ 22,225未汉化DSH
73.6
新词雷达zhuyansen/new-term-radar
new-term-radar新词雷达
★ 2,049已汉化MCP
72.8
插件生态导航0xsline/awesome-deepseek-harness
安装 贡献指南 DeepSeek Docs 公开插件目录 Issues
★ 1,188已汉化DSH
72.6
技能注册中心iflytek/skillhub
企业级开源智能体技能注册中心——发布、发现并管理组织内可复用的技能包。
★ 5,370已汉化DSH
71.9
插件市场目录imsai-sh/awesome-deepseek-harness-plugins
面向 DeepSeek Harnessdsh生态的社区插件目录,共收录 13941 个插件含 PR 收录与…
★ 355已汉化DSH
71.8
插件精选清单Anil-matcha/awesome-dsh-plugin
DeepSeek Harnessdsh精选指南——DeepSeek…
★ 1,013已汉化DSH
71.7
这是你的仓库?认领条目