mirage
strukto-ai
The World's First Unified Virtual Filesystem For AI Agents
PROJECT TOPICS
INSTALL REFERENCE
dsh plugin --profile web add github:slywalker2006/dsh-passwords
该命令指向仓库当前默认分支;尚无绑定当前 commit 的完整验证结果。
PROJECT README
English | 简体中文
给 DeepSeek Harness(dsh)加一层服务器级网关,把它从「本地单机工具」升级成能多人远程使用的多租户平台。
dsh 自带的网页界面没有登录、没有权限、没有用量控制——放到服务器上,任何拿到地址的人都能用,还会白白消耗你的模型额度。dsh-passwords 在 dsh 前面挡一层网关:没登录先看登录页;登录后按账号身份做权限与配额控制。安装只需一条命令,无需任何额外配置即可开箱即用。
一句话定位:dsh-passwords = 让 dsh 真正变成服务器产品的那一层。 企业内部分发、API 中转站给客户开子账号、团队共享一台服务器,都是它的目标场景。纯本地单机用 dsh 不需要它;但只要访问地址不是 localhost,先装它。
🏅 已收录于 Awesome DeepSeek Harness 生态索引(Infrastructure & Development)与 Awesome DSH Plugin 插件精选列表(Development & Runtime)。
主用户可以在设置页给每个子用户单独配置:
| 登录页 · 浅色 | 登录页 · 深色 | 登录页 · English |
|---|---|---|
![]() |
![]() |
![]() |
| dsh 主界面(登录后) | 聊天 / 留言 | 设置页卡片 · 账号管理 |
|---|---|---|
![]() |
![]() |
![]() |
| 设置页卡片 · 权限与配额 | ||
|---|---|---|
![]() |
node -v 查看(Linux:curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - && sudo apt-get install -y nodejs;Windows:nodejs.org 下载安装包)npm install -g @deepseek-ai/dsh,并已能正常对话(dsh 自身的模型连接配置好即可;本插件不需要任何额外配置)apt-get install -y git;Windows 去 git-scm.com 下载(pnpm 缺了脚本会自动装)# Linux / macOS —— 方式 A:直接下载安装
curl -fsSL https://raw.githubusercontent.com/slywalker2006/dsh-passwords/main/install.sh | bash
# Linux / macOS —— 方式 B:先 clone 再装
git clone https://github.com/slywalker2006/dsh-passwords
cd dsh-passwords
bash install.sh
Windows:下载仓库里的 install.bat 双击运行(或 clone 后运行)。它会自动把项目装到 %USERPROFILE%\dsh-passwords 并完成全部配置。Windows 上绑 80/443 不需要管理员权限;端口被占用时网关会以错误码 32 提示。
npm 用户:
npm install -g dsh-passwords
dsh-passwords install # 生成随机 SETUP_KEY + 注册插件 + 应用补丁(等价一键安装)
(dsh-passwords --version 看版本;dsh-passwords serve-gateway 手动启动网关。)
脚本自动完成:装依赖 → 编译 → 生成随机 SETUP_KEY → 注册为 dsh 插件 → 应用远程设置补丁。
装完屏幕最后会显示首次配置密钥(SETUP_KEY),同时也写进了安装目录的 setup-key.txt。首次配置成功后该文件会被自动删除,.env 里的密钥也会自动固化成独立变量并轮换——你不需要手动处理。
dsh web;密码门本身无需任何额外配置)——密码门会被自动拉起,不需要任何额外启动命令https://<服务器IP>.sslip.io——第一次访问会自动进入「首次配置」页,输入 SETUP_KEY,创建主用户(不用手动输入 /gateway/setup)https://<服务器IP>.sslip.io 都会先过登录页别忘了在防火墙和云服务商安全组里放行 80 和 443 端口(开不了 80 的机器见下面的「部署场景矩阵」)。
不需要 systemd,不需要手动启动网关进程,不需要给 dsh 加任何启动参数:
dsh 启动 → 插件被加载 → 插件自动拉起密码门(日志就在 dsh 控制台里)
dsh 退出 → 密码门跟着停(不会留僵尸进程占端口)
node dist/cli.js serve-gateway 手动跑,或自己配 systemd 也行。DSH_PASSWORDS_NO_AUTOSTART=1。<IP>.sslip.io 域名向 Let's Encrypt 签发 90 天证书;到期前 30 天自动续期(新证书热加载,无需重启),全程零操作.env 加一行 MCP_GATEWAY_DOMAIN=你的域名,域名 A 记录指向服务器即可,证书自动改签域名版| 错误码 | 含义 | 怎么办 |
|---|---|---|
| 30 | 证书签发失败 | 检查 80/443 是否放行(防火墙 + 云安全组都要开)、80 是否被占用、能否连通 Let's Encrypt |
| 31 | 拿不到公网 IP/域名 | 服务器没有公网 IP,或探测失败。有域名就设 MCP_GATEWAY_DOMAIN;纯内网用走 HTTP 模式 |
| 32 | 端口被占用 | 换端口(.env 的 MCP_GATEWAY_PORT)或释放被占端口 |
为什么地址里有个
.sslip.io?浏览器要求证书上的名字和网址一致,而 Let's Encrypt 不给纯 IP 签发证书,<IP>.sslip.io是免费借名服务。直接输裸 IP 的https://仍会提示主机名不匹配,属正常现象——从 80 端口入口进会自动跳到正确地址。
自动 HTTPS 的证书验证(Let's Encrypt http-01)要求 LE 直连你服务器公网 IP 的 80 端口——安全组、系统防火墙、NAT 转发一层都不能少。开不了 80 也不用慌,对号入座:
| 场景 | 做法 | 用户看到的 | 需要放行 |
|---|---|---|---|
| ✅ 公网服务器,80/443 都能开 | 什么都不用做(默认) | HTTPS(自动证书) | 80 + 443 |
| ✅ 有自己的域名证书 | .env 填 MCP_GATEWAY_TLS_CERT/KEY,端口随便改 |
HTTPS(你的证书) | 只有你的网关端口,80 完全不用 |
| ✅ 机器上已有 nginx/caddy 反代 | 反代在 80/443 用真实证书终结 TLS 并转发到密码门;.env 设 MCP_GATEWAY_AUTO_TLS=0 + 高位端口,密码门只监听回环 |
HTTPS(反代的证书) | 反代管 80/443,密码门零公网暴露 |
| ✅ 域名挂在 Cloudflare | CF 边缘终结 TLS 转发到源站任意端口(配置同反代思路) | HTTPS(CF 证书) | 源站只对 CF 开放 |
| ⚠ 无公网 IP / 纯内网 | scripts/start-http.mjs 或 .env 设 AUTO_TLS=0 |
HTTP 明文 | 任意端口 |
| ⚠ 只有裸 IP 且 80 开不了 | 只能 HTTP(协议限制:http-01 固定走 80,裸 IP 又没有 DNS 可验证) | HTTP 明文 | 任意端口 |
补充:http-01 验证只在签发和续期时访问 80 端口(每次几秒钟,约每 60 天一次);
MCP_GATEWAY_REDIRECT_PORT默认就是 80,同时承担证书应答和 301 跳转两件事。
密码门默认拒绝以明文 HTTP 运行。确实只能内网用、且接受风险的话:
node scripts/start-http.mjs [端口] # 默认 8080,会弹 y/N 确认
脚本会先显示明文风险警告,输入 y 才启动。明文 HTTP 下密码与会话 Cookie 可能被网络中间人嗅探——公网部署请优先使用自动 HTTPS(默认模式,无需配置,只有证书实在签不出来时才用 HTTP 模式)。
更彻底的做法:.env 里写 MCP_GATEWAY_AUTO_TLS=0 和 MCP_GATEWAY_PORT=8080,之后 dsh 启动时插件会直接以 HTTP 模式拉起密码门。
登录 dsh 后,打开 设置 → 插件,能看到"dsh-passwords · 密码门"卡片。里面可以:
| 功能 | 谁可用 | 说明 |
|---|---|---|
| 远程设置 + 重载补丁 | 所有登录用户 | 远程设置已应用(强制启用);dsh 升级后若设置页出现异常,点"重载补丁"一键修复(自动重启网页服务并刷新页面,不用 SSH) |
| 修改密码 | 本人改自己;主用户可改任何人 | 改密后旧会话全部立即失效,需重新登录 |
| 修改用户名 | 本人改自己;主用户可改任何人 | 改名后需用新用户名重新登录 |
| 子用户管理 | 仅主用户 | 创建/删除子用户(子用户可用登录页进入,但没有管理权限) |
| 子用户权限 | 仅主用户 | 工作区白名单、每小时 token 上限、每日时长上限、沙盒级别、上传/git 下载开关、封禁 |
| 聊天 / 留言 | 所有登录用户 | 左下角聊天按钮,支持标签(议题/拉取请求/讨论/公告/问题) |
| 变量 | 默认 | 说明 |
|---|---|---|
SETUP_KEY |
安装脚本自动生成 | 首次配置密钥;JWT 会话密钥也从它派生,安装后别删 |
MCP_JWT_SECRET |
空(从 SETUP_KEY 派生) | 会话签名密钥。生产环境建议独立设置(openssl rand -hex 32),SETUP_KEY 泄露时不连带会话伪造 |
MCP_DB_PATH |
./data/platform.db |
数据库文件(SQLite 自动建库,不需要 MySQL) |
MCP_DB_ENC_KEY |
空 | 数据加密密钥。openssl rand -hex 32 生成。设了就不能换,换钥匙旧数据全废 |
MCP_GATEWAY_HOST |
0.0.0.0 |
网关监听地址 |
MCP_GATEWAY_PORT |
443 |
网关端口 |
MCP_GATEWAY_UPSTREAM |
http://127.0.0.1:3080 |
dsh 网页地址(插件自动指向 dsh 实际端口,一般不用改) |
MCP_GATEWAY_REDIRECT_PORT |
80 |
80 端口:ACME 证书验证 + 301 跳转 443 |
MCP_GATEWAY_DOMAIN |
空 | 自己的域名;留空自动用 <公网IP>.sslip.io |
MCP_GATEWAY_AUTO_TLS |
开 | 留空=自动;0 关闭(明文 HTTP,危险) |
MCP_GATEWAY_ACME_EMAIL |
空 | 证书到期提醒邮箱(可选) |
MCP_GATEWAY_ACME_STAGING |
关 | 1=用 LE 测试环境签发(调试用,浏览器不信任) |
MCP_GATEWAY_TLS_CERT / MCP_GATEWAY_TLS_KEY |
空 | 两个都填 = 用你自己的证书(优先于自动 HTTPS) |
MCP_GATEWAY_PUBLIC_HOST |
空 | 跳转固定用的公网 IP/域名(防 Host 伪造反射) |
MCP_DSH_ROOT |
自动探测 | dsh 安装目录(@deepseek-ai/dsh 所在处),探测不到时手动指定 |
MCP_DSH_RESTART_SERVICE |
dsh-web |
重载补丁后自动重启的 dsh systemd 服务名;显式留空不自动重启 |
DSH_PASSWORDS_ENV_FILE |
空 | 手动指定 .env 路径(插件自动传,一般不用填) |
node dist/cli.js audit --limit 20 # 看最近 20 条审计日志(自动解密)
node dist/cli.js patch status # 看远程设置补丁状态
node dist/cli.js patch # 重载补丁(重新应用 + 重启 dsh-web)
node dist/cli.js serve-gateway --port 9000 # 手动启动网关并换端口
node scripts/start-http.mjs 8080 # 明文 HTTP 模式(危险,y/N 确认)
SETUP_KEY 重新创建主用户即可。node -e "const {DatabaseSync}=require('node:sqlite');const db=new DatabaseSync('data/platform.db');db.exec('DELETE FROM users;')",重启后重新走首次配置。MCP_GATEWAY_PORT 改成高位端口(如 8443)并自行做端口转发。duplicate loader entry id? 你在 profile 里用过 dsh plugin add。它会把 profile 里所有声明 dsh.bundle 的依赖全部加进 bundles 层,与已装的其它插件重复时 dsh 直接启动失败。卸载 dsh-passwords 后改用 node scripts/register-plugin.mjs 精确注册(只追加本插件一个条目)。npm config set allow-scripts=@deepseek-ai/dsh-subprocess-local,koffi,node-pty,@google/genai,protobufjs --location=user,然后重新 npm install -g @deepseek-ai/dsh(本项目自身没这个问题,是 dsh 的依赖要跑原生构建)。crypto.randomUUID is not a function? 旧版网关没有 HTML 注入兼容层,更新代码后强刷浏览器(Ctrl+Shift+R)。.env 里的密钥解不开;密码本身只有 bcrypt 哈希,本来就没有明文。MCP_DB_ENC_KEY? 不行。这个密钥一旦启用就不能换,换了一切历史数据都解不开。备份数据库时必须连 .env 一起备份。no-cache,浏览器每次都要全部重新下载。网关已对 /assets/* 和带 rev= 的 /plugins/* 强制一年期 immutable 缓存(文件名/rev 都是内容哈希,dsh 更新会自动换新地址)。升级后第一次访问仍会完整下载一次,之后刷新秒进;如果还慢,强刷一次浏览器(Ctrl+Shift+R)让新响应头生效。curl -s -o /dev/null -w "TCP:%{time_connect}s TLS:%{time_appconnect}s\n" https://你的地址/gateway/login——TLS 那项正常是几十毫秒。TCP 快、TLS 也快但还是慢的话,就是你的网络到服务器的链路延迟,代码解决不了。Windows 用户建议直接用
install.bat;本节以 Linux 为例,步骤等价。
git clone https://github.com/slywalker2006/dsh-passwords && cd dsh-passwordsnpm install && npm run buildcp .env.example .env,把 SETUP_KEY 改成随机串(openssl rand -hex 24)node scripts/register-plugin.mjs(等价于把 link:$(pwd) 加进 ~/.dsh/profiles/web/package.json 的 dependencies 和 dsh.profile.bundles 再 pnpm install。不要用 dsh plugin add,原因见常见问题)node dist/cli.js patch(找不到 dsh 目录就用 MCP_DSH_ROOT=/path/to/@deepseek-ai/dsh 指定)之后同样:启动 dsh → 密码门自动拉起 → 打开 https://<你的地址> 完成首次配置。
账号密码只存 bcrypt 哈希;用户名、IP、审计记录加密落盘;登录/失败全程审计;证书签发失败拒绝启动(不降级明文)。所有密钥都在你自己的 .env 和数据库里,源码公开不影响安全。
allow_upload / allowGitDownload 权限门控,新子用户默认禁 git 下载(含 dsh-uploads 下载等外带通道),主用户按需开启,子用户无法枚举或外带共享存储中的文件。%2f..%2f / %252f.. 等 SPA 壳绕过变体全部拦截。setup-key.txt、把 JWT/内部/字段加密密钥固化成独立 .env 变量、并轮换 SETUP_KEY——无需手动处理;如果你在已初始化的实例上部署(没走首次配置页),才需要手动删一次 setup-key.txt;.env 里显式设置独立的 MCP_JWT_SECRET(openssl rand -hex 32)与 MCP_DB_ENC_KEY——首次配置后这些值已自动固化,手动设置只是换一把新的;MCP_DSH_RESTART_SERVICE 指向正确的 systemd 服务名。界面为中英双语,跟随 dsh 的语言设置:
LANG / LC_ALL 环境变量(en 开头即英文)。BSD 3-Clause © 2026 slywalker2006——自由使用、修改、分发,保留版权声明即可。
本项目是 dsh 的独立扩展,与 DeepSeek 无隶属关系。dsh 本身按它自己的许可证(MIT)授权。
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: security。