Turns DeepSeek Harness into a server-grade multi-tenant platform: remote access + auto HTTPS, subuser permissions & token/daily quotas, sandbox enforcement, encrypted auth & audit log.
Install
# from npm (prebuilt)
dsh plugin --profile web add dsh-passwords
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:slywalker2006/dsh-passwords
Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).
README
简体中文 | English
Features · Quick start · First-run setup · Uninstall · Automatic HTTPS · Deployment topologies · Configuration · FAQ · Security · Contributing
Features
- Login: first-run setup creates the owner account; every later visit goes through the login page; sessions last 12 hours
- Automatic HTTPS: issues and renews Let's Encrypt certificates, redirects port 80 to 443, zero configuration
- Multi-tenant: one owner plus any number of subusers; account management lives in the dsh settings page
- Permissions and quotas: workspace allowlists, per-session toggles, hourly token caps, daily time caps, three sandbox tiers, upload/download switches, ban
- Session grants: workspace permission no longer implies access to every session; the owner grants sessions individually; archive state stays consistent between workspace and session lists
- Operator view: the owner sees all workspaces and sessions and can download non-sensitive regular files
- Auditing and security: login rate limiting and lockout, audit log, SQLite encryption at rest, logout revokes sessions
- Settings card: patch reload, software updates, account and permission management, in-app messaging, bilingual zh/en UI
Screenshots
| Login · Light | Login · Dark | Login · English |
|---|---|---|
| dsh main UI · signed in | Chat / Messaging | Settings card · Accounts |
|---|---|---|
| Settings card · Permissions and quotas | ||
|---|---|---|
Quick start
Prerequisites
Host installs need Node.js 22.19+ or 24+, a working dsh installation, and git. The compatibility gate accepts stable DSH 0.1.7 and its alpha/rc prereleases; the current working tree pins development and bundled Docker to 0.1.7-rc.2. Compatibility targets also retain the full 0.1.6 / 0.1.5 lines and the 0.1.2 / 0.1.3 API boundaries. The alpha.2 profile (v2.7.4) has been deployed and validated on the test server. Docker installs only need Docker Engine or Docker Desktop and a DeepSeek API key.
Install
Five install methods, pick one. Host installs automatically install dependencies, build, generate a SETUP_KEY, register the dsh plugin and apply the remote-settings patch; an existing .env is never overwritten, so re-running is safe.
# 1. Linux / macOS one-liner
curl -fsSL https://raw.githubusercontent.com/slywalker2006/dsh-passwords/main/install.sh | sudo bash
# 2. Clone first, then install
git clone https://github.com/slywalker2006/dsh-passwords && cd dsh-passwords
sudo bash install.sh
# 3. npm global install, works on any platform
npm install -g dsh-passwords
dsh-passwords install
On Windows download install.bat from the repository and run it. The default install directory is %USERPROFILE%\dsh-passwords.
# 4. Docker
docker run -d \
--name dsh-passwords \
--restart unless-stopped \
--env-file .env \
-p 127.0.0.1:3088:3088 \
-v dsh-home:/data/dsh \
-v dsh-passwords-state:/data/dsh-passwords \
skywalker237234/dsh-passwords:2.7.5
.env needs at least DEEPSEEK_API_KEY. Set MCP_GATEWAY_PUBLIC_HOST to the domain you actually use. The host publishes port 127.0.0.1:3088 only while the container listens on 0.0.0.0:3088; terminate TLS on nginx or Caddy for public access. The image bundles DSH 0.1.7-rc.2 (the pinned release of the DSH 0.1.7 line; image runtime acceptance has not been performed for this pin); initialization is complete when healthz and readyz both return ok:true.
Notes:
- Host installs default to
/opt/dsh-passwords; override withDSH_PASSWORDS_DIR. A recognized existing dsh-passwords directory resumes the idempotent installer in place; another existing target aborts - The SETUP_KEY is printed when the install finishes and written to
setup-key.txtin the install directory - The two Docker volumes hold the dsh profile and the
.env, database and certificates; deleting them deletes your data - Emergency cleanup does not self-delete from inside Docker. For Compose deployments run
docker compose down -v; for the documenteddocker rundeployment, rundocker rm -f dsh-passwordsfollowed bydocker volume rm dsh-home dsh-passwords-state(both permanently remove volume data) - For split-container deployments set
MCP_DSH_PATCH_ALLOW_BIND_ALL=1on the dsh container so the gateway container can reach dsh web
First-run setup
- Start dsh:
dsh web. Docker users skip this; the container starts it automatically. - Open
https://<server address>in a browser; the first visit enters the setup page. - Enter the SETUP_KEY to create the owner account. Every later visit to this address goes through the login page.
After setup completes, setup-key.txt is deleted automatically and the keys in .env are consolidated and rotated.
Docker users need nginx or Caddy to proxy 80/443 to http://127.0.0.1:3088 first; read the one-time SETUP_KEY with docker exec dsh-passwords cat /data/dsh-passwords/setup-key.txt.
Uninstall
For a host installation, run this from the dsh-passwords installation directory:
node dist/cli.js uninstall
# A global npm installation can also use:
dsh-passwords uninstall
The command removes only the dsh-passwords link and bundle from the DSH web profile, then rolls back dsh patches managed by this plugin. Other plugins and bundles remain in place. Restart dsh-web when prompted.
It does not delete the installation directory, .env, database, TLS/ACME certificates, or other plugins. If profile dependency reconciliation or patch rollback fails, the original profile is restored to avoid a partial uninstall. For Docker, stop and remove the deployment using its Compose or container configuration; do not remove named volumes unless you also intend to permanently erase data.
Automatic HTTPS
By default the gateway detects the public IP and issues a 90-day Let's Encrypt certificate for <IP>.sslip.io, renewing automatically 30 days before expiry with hot reload. For your own domain set MCP_GATEWAY_DOMAIN. Issuance failure refuses to start and never falls back to plaintext; renewal failure keeps the still-valid old certificate and retries in the background.
| Code | Meaning | Action |
|---|---|---|
| 30 | Certificate issuance failed | Check 80/443 availability and that Let's Encrypt is reachable |
| 31 | No public IP or domain | Set MCP_GATEWAY_DOMAIN, or use HTTP mode |
| 32 | Port occupied | Change MCP_GATEWAY_PORT or free the port |
The <IP>.sslip.io name exists because Let's Encrypt does not issue certificates for bare IPs. Visiting the bare-IP https address warns about a hostname mismatch; entering through port 80 redirects to the correct address.
Deployment topologies
| Scenario | Approach |
|---|---|
| Public server with 80/443 open | Default configuration, automatic HTTPS |
| Existing domain certificate | Set MCP_GATEWAY_TLS_CERT / MCP_GATEWAY_TLS_KEY; port 80 not needed |
| Existing nginx / Caddy reverse proxy | Terminate TLS at the proxy, set MCP_GATEWAY_AUTO_TLS=0 and a high port, gateway listens on loopback only |
| Cloudflare | CF terminates TLS and forwards to origin, same approach as a reverse proxy |
| Internal network / bare IP without port 80 | Use HTTP mode |
http-01 validation only touches port 80 during issuance and renewal, about once every 60 days.
HTTP mode
Plaintext HTTP is refused by default. When an internal-only deployment truly needs it:
node scripts/start-http.mjs [port] # default 8080, asks for confirmation
Alternatively, set MCP_GATEWAY_AUTO_TLS=0 and MCP_GATEWAY_PORT=8080 in .env; the plugin starts the gateway in HTTP mode. This mode needs no public IP, DNS, ACME, or external CDN and is suitable for an internal network. The initial installation still needs npm/GitHub access, or a prepared project tarball, dependency cache, and local DSH installation. Model replies still require an upstream provider such as DEEPSEEK_API_KEY; without a model service, login, permissions, files, and administration remain available but model generation does not.
The gate card in dsh settings
After signing in, open Settings to find the "dsh-passwords" card.
| Feature | Who | Notes |
|---|---|---|
| Patch reload | Owner only | Re-applies the patch and restarts the web service when a dsh upgrade breaks the settings page |
| Software updates | Status visible to all, actions owner only | Auto check, throttled download, idle-window install and restart, see below |
| Change password / username | Self; owner can act on anyone | Password change revokes all old sessions |
| Subuser management | Owner only | Create and delete subusers |
| Subuser permissions | Owner only | Workspace allowlist, per-session grants, token and time caps, sandbox tier, upload/download switches, WebSocket path grants, ban |
| Chat / messaging | All signed-in users | Tagged messages; subuser messages default to DMs to the owner, only the owner can broadcast |
| Sign out | All signed-in users | Ends the current session |
Passwords require at least 12 characters with upper, lower, digit and symbol.
Software updates
- Version discovery uses GitHub Releases; packages always come from the npm registry, verified against the release's
dist.integritysha512 - Automatic mode: checks every 24 hours, downloads throttled after finding a new version, installs and restarts after the platform has been idle for one hour; the owner can install immediately
- Manual mode: check only discovers versions; the first click downloads, the second click installs and restarts
- Installs preserve
.env,data/, the database, TLS material and the dsh profile; failures roll back - Docker updates require explicit
MCP_DSH_DOCKER_SELF_UPDATE=1plus the Compose variables; without them only host-side manual commands are shown. A Docker socket grants the container control of the host; enable only in trusted deployments
Configuration reference
| Variable | Default | Description |
|---|---|---|
SETUP_KEY |
Generated by installer | First-run setup key, rotated automatically after setup |
MCP_JWT_SECRET |
Derived from SETUP_KEY | Session signing key; set independently with openssl rand -hex 32 in production |
MCP_DB_PATH |
./data/platform.db |
SQLite database path |
MCP_DB_ENC_KEY |
empty | Field encryption key; cannot be changed once set. Back up the database together with .env |
MCP_GATEWAY_HOST / MCP_GATEWAY_PORT |
0.0.0.0 / 443 |
Gateway listen address and port |
MCP_GATEWAY_UPSTREAM |
http://127.0.0.1:3080 |
dsh web address, pointed automatically |
MCP_GATEWAY_SSH_ENDPOINTS |
empty | Third-party endpoint registry (comma-separated; one variable for both transports and both capabilities). Writing a path is the registration itself: a rule is [owner:][ws:|http:]path (prefixes optional, order-agnostic). owner: rules are owner-only (subusers get 403 on both transports); any other rule requires BOTH the owner registration and the subuser's shared SSH-endpoint/official-terminal toggle — neither alone grants third-party access. The alpha.2 official terminal does not need registration and uses the same toggle; its known HTTP and Remote mux methods are handled explicitly by the gateway. ws:/http: restrict a rule to one transport; a bare path applies to both. Paths match exactly, or a trailing /* matches direct child paths only. Unregistered third-party paths (/api/* and root-level plugin routes) are denied for subusers. When DSH_PASSWORDS_ENV_FILE is set, the gateway polls that .env every 5 seconds and applies valid changes without a restart; otherwise restart the gateway after editing .env. No plugin-specific auto-detection is performed. |
MCP_GATEWAY_PLUGIN_COMPAT |
off |
Third-party plugin compat layer: off (default; unregistered third-party paths stay fail-closed) or on to enable fine-grained adapters for known plugins (file-tree whitelisting, upload/download gating, content sanitising). |
MCP_GATEWAY_REDIRECT_PORT |
80 |
ACME validation and 301 redirect port |
MCP_GATEWAY_DOMAIN |
empty | Custom domain; empty uses <public IP>.sslip.io |
MCP_GATEWAY_AUTO_TLS |
on | 0 disables automatic HTTPS |
MCP_GATEWAY_TLS_CERT / MCP_GATEWAY_TLS_KEY |
empty | Your own certificate, takes precedence over automatic HTTPS |
MCP_GATEWAY_PUBLIC_HOST |
empty | Fixed redirect target, guards against Host spoofing |
MCP_GATEWAY_ACME_EMAIL / MCP_GATEWAY_ACME_STAGING |
empty / off | Renewal contact email / LE staging |
MCP_DSH_ROOT |
auto-detected | dsh installation directory |
MCP_DSH_RESTART_SERVICE |
dsh-web |
systemd service restarted after patch reload |
MCP_DSH_AUTO_UPDATE |
on | Deployment-level auto-update master switch |
MCP_DSH_UPDATE_MAX_BPS |
1MiB/s | Automatic download throttle; can only be lowered |
MCP_DSH_DOCKER_SELF_UPDATE / _COMPOSE_DIR / _COMPOSE_FILE / _IMAGE / _SOCKET |
off / empty | Docker in-app update switch and Compose settings |
MCP_DSH_PATCH_ALLOW_BIND_ALL |
off | Allows dsh web to bind 0.0.0.0 for split-container topologies |
DSH_PASSWORDS_ENV_FILE |
empty | Explicit .env path |
Common commands
node dist/cli.js audit --limit 20 # last 20 audit entries
node dist/cli.js patch status # remote-settings patch status
node dist/cli.js patch # reload patch and restart dsh-web
node dist/cli.js serve-gateway --port 9000 # start the gateway manually
DSH_PASSWORDS_NO_AUTOSTART=1 dsh web # keep the gateway from auto-starting
curl -s https://address/gateway/healthz # liveness check
curl -s https://address/gateway/readyz # readiness check, includes database
FAQ
The users table is empty; enter the SETUP_KEY to recreate the owner account.
Stop the service, clear the users table and restart:
node -e "const {DatabaseSync}=require('node:sqlite');const db=new DatabaseSync('data/platform.db');db.exec('DELETE FROM users;')"
See the table under "Automatic HTTPS".
Ports below 1024 require root on Linux; switch to a high MCP_GATEWAY_PORT and forward as needed.
dsh plugin add adds every bundle-declaring dependency to the bundles layer and conflicts. Uninstall and register precisely with node scripts/register-plugin.mjs.
Allow install scripts and reinstall:
npm config set allow-scripts=@deepseek-ai/dsh-subprocess-local,koffi,node-pty,@google/genai,protobufjs --location=user
No. Sensitive fields are encrypted or hashed, passwords exist only as bcrypt hashes, and decryption requires the .env keys.
No; changing it makes all existing data undecryptable.
The gateway force-caches content-hashed static assets for one year; the first visit after an upgrade downloads fully once, later loads are instant. The gateway adds about 1-2ms per request; check the TLS handshake first:
curl -so /dev/null -w "TLS:%{time_appconnect}s\n" https://address/gateway/login
The bottleneck is usually the network path to the server.
Manual install
v2.7.5 accepts stable DSH
0.1.7and its alpha/beta/rc prereleases, with the working tree and bundled Docker pinned to0.1.7-rc.2; it also retains compatibility targets for the full0.1.6/0.1.5lines and the0.1.2/0.1.3API boundaries. The 2.7.5 test-server deployment, health/readiness, patch status, and multiuser flows were checked. The installer requires Node.js22.19+or24+, registers the plugin, detects dsh, and applies the compatibility patch.
git clone https://github.com/slywalker2006/dsh-passwords && cd dsh-passwordsnpm install && npm run buildcp .env.example .envand set SETUP_KEY toopenssl rand -hex 24node scripts/register-plugin.mjsto register the pluginnode dist/cli.js patchto apply the patch; setMCP_DSH_ROOTif the dsh directory is not found
Then start dsh, the gateway comes up automatically, and "First-run setup" finishes initialization.
Security and privacy
Passwords are stored only as bcrypt hashes; usernames, IPs and audit records are encrypted at rest; certificate issuance failure refuses to start the gateway.
- Failed-login lockout backs off per round from 1 to 60 minutes; the owner account cannot be globally locked out by rotating IPs
- 30 failures from one IP within 15 minutes trigger a 30-minute IP-level throttle, countering cross-username password spraying
- Logout revokes the token server-side; password and username changes invalidate all old sessions
- Third-party plugin operator endpoints are owner-only; uploads and downloads are permission-gated and new subusers start with downloads disabled
- Request timeouts and connection limits mitigate slowloris; path normalization blocks
%2fand double-encoding variants - After first-run setup the system deletes
setup-key.txtand consolidates independent secret variables automatically
Language
The UI is bilingual zh/en and follows the dsh language setting. The login page has a manual switch that persists; the CLI follows LANG / LC_ALL.
Version compatibility
Latest published release: 2.7.5, pinned to DSH 0.1.7-rc.2. The DSH compatibility gate accepts the stable 0.1.7 line and SemVer alpha/beta/rc prereleases. Compatibility targets also retain the whole DSH 0.1.6 / 0.1.5 lines and the 0.1.2 / 0.1.3 API boundaries. The npm package ships prebuilt dist, TypeScript sources, and all scripts; Docker and npm are built from the same source revision.
Contributing
- Before opening an issue, read the community checklist and use the bug or feature template
- For code contributions, read CONTRIBUTING.md and use the PR template; keep changes focused and include test evidence
- Run
npm ci && npm run build && npm testbefore submitting; CI runs automatically on Node 22/24
Contributors
If you find this useful, give it a star.
Report an issue · Releases · npm package · Awesome listings
License
GNU GPL v3.0 only, full text in LICENSE.
This project is an independent extension of dsh and is not affiliated with DeepSeek.
Links
More in this category
toby-bridges/api-relay-audit★ 860
Runs local security audits of AI API relays and LLM proxies from DeepSeek Harness, producing Markdown reports for prompt injection, model substitution signals, tool-call rewriting, error leakage, stream integrity, and profile-gated Web3 risks.
SeaOf0/dsh-redteam-model★ 638
Authorized-security DSH collection: nine work modes (redteam coordinator, pentest, code audit, binary analysis, attack-defense, AV evasion, incident response, cloud security, CTF solving) and fifteen runtime plugins, managed from a settings page with one-click deploy, install, update and uninstall.
howmp/dsh-pentest★ 558
Authorized pentest mode for DeepSeek Harness — exploration chain, assets and findings with a Web view.
PerryLink/dsh-auto-review★ 206
Second-model auto-review on the approval answerer chain: a read-only reviewer subagent returns structured allow/deny verdicts with reasons, fail-closed by default.
NanmiCoder/dsh-auto-mode★ 163
Adds an Auto permission preset between Workspace Write and Full access: routine work stays in the official workspace-write sandbox while the current session model reviews escalation and destructive calls, granting one exact wider access once, asking when the intent is ambiguous, and denying critical paths.
PerryLink/dsh-permission-rules★ 114
Claude Code-style declarative permission rules: ordered allow/deny/ask YAML rules matching tool names, arguments, workspace paths, and agent identity on the tools/pre-execute waterfall, with full session-log audit, dry-run mode, and hot reload.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.