deepseek-harness
deepseek-ai
DeepSeek Harness: Everything is a Plugin.
PROJECT TOPICS
PROJECT README
DeepSeek Harness(dsh)的登录门卫插件。dsh 的 Web UI 默认只监听 127.0.0.1:3080,禁止外部访问;本插件在外部再开一个入口(默认 0.0.0.0:3081),访问者先通过用户名密码登录,登录成功后流量被全量反向代理到 dsh 的 Web UI(HTTP 与 WebSocket 都支持),功能零缺失。
零运行时依赖(只用 Node.js 内置模块),Node 22+ ESM。
0.0.0.0 会裸奔在公网上,任何人可访问;127.0.0.1。首次访问未初始化时,会进入 /setup 引导页,输入一次性令牌并创建管理员账号:

浏览器 ──HTTP/WS──▶ 0.0.0.0:3081(门卫:登录校验 + 会话 Cookie)
│ 通过校验后全量反代(改写 Host/Origin/Sec-Fetch-Site 为 loopback 形态)
▼
127.0.0.1:3080(dsh Web UI,信任围栏放行,特权 API 全可用)
关键点:反代时把请求头里的 Host/Origin/Sec-Fetch-Site 改写为 loopback 形态,让 dsh 把请求当作“本机请求”信任放行;WebSocket 升级请求同样先校验会话再转发。
用 dsh 标准插件命令安装(本项目是标准 dsh.bundle 插件,无需手改 profile 配置):
# 本地目录安装(link 形式,profile 直接引用本目录,改源码无需重装)
dsh plugin --profile web add /path/to/dsh-login-gateway
# 卸载
dsh plugin --profile web remove dsh-login-gateway
安装/卸载后重启 dsh 生效。
获取一次性初始化令牌(二选一):
方式 A:看 dsh 启动终端或服务日志输出
插件会直接输出一行提示,内容类似:
[login-gateway] 登录门卫未初始化,请访问 http://<主机>:3081/setup 并输入一次性令牌:ABCD-EFGH-IJKL-MNOP-QRST-UVWX-YZ12-3456
日志示例:

方式 B:读取令牌文件
令牌同时会写入用户文件同目录下的 setup-token.txt(权限 0600,内容只有令牌本身):
cat ~/.dsh-login-gateway/setup-token.txt
浏览器打开 http://<主机>:3081/setup,输入令牌、管理员用户名、密码(至少 8 位)与确认密码,点击“完成设置”。
初始化完成后会跳转到登录页,用刚创建的账号登录,即可进入 dsh。
说明:新装没有默认账号,必须走
/setup引导创建。未初始化时访问/会自动302跳转到/setup。令牌只在未初始化阶段生成;初始化完成后/setup会返回410,setup-token.txt也会被自动删除。
本项目是标准的 dsh.bundle 插件(package.json 声明 dsh.bundle.patch,随包自带 cordis.patch.yml 挂载层),用 dsh 官方插件命令管理,无需手改 profile 配置:
dsh plugin --profile web add /path/to/dsh-login-gateway
命令会把本目录以 link: 形式装进 profile(~/.dsh/profiles/web/),并自动把包名追加到 profile 的 dsh.profile.bundles 层列表。安装后重启 dsh 生效。
开发调试提示:
link:形式下 profile 直接引用本目录,改源码后重启 dsh 即可生效,无需重装。
dsh plugin --profile web remove dsh-login-gateway
重启 dsh 后,门卫端口 3081 停止服务,外部访问恢复为“无法访问”。
可选清理:删除门卫的用户数据目录(账号、令牌文件):
rm -rf ~/.dsh-login-gateway/
随包挂载层只提供默认配置。如需改端口、超时等,在 profile 目录(如 ~/.dsh/profiles/web/)的 cordis.patch.yml 用户层追加覆盖(注意:补丁是整段替换 config,要写全所有项):
- id: login-gateway
config:
listenHost: '0.0.0.0'
listenPort: 3081
targetHost: '127.0.0.1'
targetPort: 3080
sessionTtlHours: 24
maxLoginAttempts: 5
lockMinutes: 5
零侵入。门卫只做三件事:在外部开一个登录入口、校验会话、把通过校验的请求反代到 dsh 的 loopback 端口。它不修改 dsh 安装目录的任何文件,也不改 dsh 自身配置逻辑;安装/卸载只影响 profile 目录(依赖与 bundles 列表),一条命令即可完全移除。卸载后 dsh 与安装前一致。
所有配置都有默认值,新装默认配置即可工作。完整配置表如下:
| 配置项 | 默认值 | 说明 |
|---|---|---|
listenHost |
0.0.0.0 |
门卫监听地址,暴露给外部 |
listenPort |
3081 |
门卫监听端口 |
targetHost |
127.0.0.1 |
dsh Web UI 监听地址 |
targetPort |
3080 |
dsh Web UI 监听端口 |
sessionTtlHours |
24 |
登录会话有效期(小时) |
maxLoginAttempts |
5 |
同一 IP 连续失败多少次后锁定 |
lockMinutes |
5 |
锁定持续分钟数 |
setupMaxAttempts |
5 |
/setup 初始化时,同一 IP 连续失败多少次后锁定 |
setupLockMinutes |
30 |
/setup 初始化锁定持续分钟数 |
proxyTimeoutMs |
60000 |
反代上游响应头等待超时(毫秒),超时返回 504;WS 握手超时取与 15s 的较小值 |
streamIdleTimeoutMs |
1800000 |
反代响应流空闲超时(毫秒,默认 30 分钟) |
maxConnections |
512 |
HTTP 服务最大并发连接数,超出后新连接被丢弃 |
userStorePath |
~/.dsh-login-gateway/users.json |
用户数据文件路径(可自定义) |
http://<主机>:3081/,输入用户名密码。成功后会种下会话 Cookie(dsh_gw_session,HttpOnly + SameSite=Strict),之后访问全部走反代,包括 WebSocket。POST /logout。页面无入口时可直接调用:curl -X POST http://<主机>:3081/logout。/ 返回登录页;其余路径返回 401 JSON。maxLoginAttempts 次会被锁定 lockMinutes 分钟。maxLoginAttempts 次也会被锁定,可防代理池分布式爆破。/setup 同样按 IP 限速,令牌错误、用户名空、密码过短、两次密码不一致都计失败。443 -> 127.0.0.1:3081)。HttpOnly + SameSite=Strict,页面无 XSS 注入点。~/.dsh-login-gateway/users.json,内含 scrypt 哈希(不可逆);写入时自动使用 0600 权限、目录自动 0700。proxyTimeoutMs 返回 504;响应头到达后改用 streamIdleTimeoutMs 空闲超时,SSE 长间隔输出不会被正常打断。maxConnections 默认 512,并显式收紧 headersTimeout、requestTimeout、keepAliveTimeout,减少慢连接占用。X-Frame-Options: DENY、Referrer-Policy: no-referrer 和 CSP;反代透传的 dsh 响应保持原样。100KB),防止恶意超大请求。重置管理员账号:删除用户文件后重启 dsh,会再次进入“未初始化”状态,并重新打印一次性令牌:
rm -f ~/.dsh-login-gateway/users.json
忘记或没看到一次性令牌:可以看 dsh 启动终端/服务日志,或读取 ~/.dsh-login-gateway/setup-token.txt。如果两者都没有,删掉用户文件并重启 dsh,会重新生成令牌。
/setup 返回 410:说明已初始化完成,设置入口已关闭,属正常现象。如需重新初始化,先删用户文件再重启。
访问 http://<主机>:3081/ 打不开:检查 dsh 是否已启动、插件挂载是否生效、端口是否被防火墙拦截。
登录后页面或接口 502:门卫反代目标 127.0.0.1:3080 不可达,确认 dsh Web UI 进程仍在运行。
用户文件损坏:启动会直接报错并给出文件路径,不会静默重置。按上面的“重置管理员账号”处理即可。
node:crypto scrypt(scrypt$N$r$p$salt$hash 自描述格式),恒定时间比较防时序攻击。Map + 过期清理(30 分钟定时 sweep)。rawHeaders 原样构造 101 响应。src/
index.js 插件主入口:配置校验、路由分发、setup 引导、HTTP 服务 + WS 升级
auth.js 密码哈希(scrypt)、会话存储、登录限速
proxy.js HTTP 反代(头改写 + hop-by-hop 剔除)与 WebSocket 升级转发
user-store.js 用户文件存储(JSON + 原子写入)
login-page.js 登录页 HTML(深色主题,单文件内联)
setup-page.js 首次启动引导页 HTML(深色主题,单文件内联)
bin/
hash.js 密码哈希生成 CLI CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: 无有效分类标签。