deepseek-harness-gateway
No description
- Stars
- 2
- Language
- TypeScript
- Created
- Sep 2, 2026
- Updated
- Sep 7, 2026
Introduction
deepseek-harness-gateway
English | 中文
A public-deployment gateway router that brings distributed DeepSeek Harness (dsh) instances on customer machines behind one managed reverse tunnel. Administrators approve machine onboarding and assign machines to users, who then fully operate the assigned machine's dsh WebUI from the gateway's web portal — with zero public exposure on the customer side.
What it does
Each customer machine runs a small plugin (dsh-gateway-agent) inside its own dsh. The plugin dials a single outbound WebSocket connection to the gateway, so the customer machine needs no inbound port, port mapping, or public IP. Once a machine is onboarded and assigned, the gateway relays browser requests to that machine's dsh WebUI over the same tunnel — the customer machine is never exposed to the internet.
Features
- Gateway — one public entry point; machine registration/approval, user assignment, seats, and audit all live at the gateway.
- Outbound-only reverse tunnel — customer dsh connects out over
wss; zero inbound listeners. - Admin approval — machines join via a pairing code + HMAC challenge-response, approved by an administrator.
- Gateway-held identity & authorization — machine identity is issued by the gateway, and all authorization is enforced at the gateway rather than on the customer machine.
- Zero-change data plane — the gateway relays the official dsh web UI (HTTP + WebSocket) untouched; no fork of dsh is required.
- Full control from the portal — operators drive the assigned machine's dsh WebUI from the gateway portal.
How it works
Public gateway (only exposed surface) Customer machine (zero inbound)
┌──────────────────────────────────────┐ ┌──────────────────────────────────────┐
│Web portal / control plane / router │ │dsh-gateway-agent plugin │
│register · assign · audit │◄── wss outbound ──│(installed in customer dsh) │
│ │ │↓ loopback │
│ │ │dsh web :3080 │
└──────────────────────────────────────┘ └──────────────────────────────────────┘
apps/gateway— the gateway server: control plane, router, HTTP API, and WebSocket upgrade handling; it also hosts the built portal.apps/web— the portal front end (Vite + React).plugins/dsh-gateway-agent— the plugin installed in a customer's dsh; it dials out to/agentand bridges the machine's local dsh web.packages/protocol/packages/store— shared wire protocol and the persistence seam.
The agent dials wss://<gateway-host>/agent and completes a pairing-code + HMAC handshake. After approval the gateway keeps the node leased via heartbeat and relays browser requests (/console/:machineId/*) to the machine's loopback dsh web (127.0.0.1:3080).
Requirements
- Node.js ≥ 20 (the gateway packages run on Node 22+).
- pnpm — this repository is a pnpm workspace.
- A DeepSeek Harness installation (web profile) on each customer machine, to host the agent plugin.
Installation
Clone and install dependencies:
git clone <this-repo-url>
cd deepseek-harness-gateway
pnpm install
Run the gateway server:
pnpm --filter @januory/dsh-gateway-server dev # http://127.0.0.1:3300/health
Run the portal front end in development (proxies /health and /agent to the gateway on 3300):
pnpm --filter dsh-gateway-web dev
Build the portal so the gateway serves it statically at the root:
pnpm --filter dsh-gateway-web build
Install the gateway from npm (a prebuilt dshgw CLI that bundles the server + portal):
npm install -g @januory/dsh-gateway-server
dshgw # http://127.0.0.1:3300/health
Runtime configuration — each setting is accepted as a dshgw CLI flag, an
environment variable, or a built-in default (CLI flag > env var > default):
| Environment variable | CLI flag | Default |
|---|---|---|
DSH_GATEWAY_HOST | --host <addr> | 127.0.0.1 |
DSH_GATEWAY_PORT | --port <n> | 3300 |
DSH_GATEWAY_DB_PATH | --db <path> | ./gateway.db |
DSH_GATEWAY_ADMIN_ID | --admin-id <id> | admin |
DSH_GATEWAY_ADMIN_PASSWORD | --admin-password <pw> | admin |
DSH_GATEWAY_PAIRING_CODES | --pairing-codes <a,b> | (none) |
DSH_GATEWAY_WEB_DIST | --web-dist <dir> | auto-detect |
DSH_GATEWAY_TRUST_PROXY | --trust-proxy <0|1> | 0 |
DSH_GATEWAY_COOKIE_SECURE | --cookie-secure <0|1> | auto (via https) |
DSH_GATEWAY_ALLOW_DEFAULT_ADMIN | --allow-default-admin 1 | off |
DSH_GATEWAY_LOGIN_IP_MAX | (env only) | 10 |
DSH_GATEWAY_LOGIN_IP_WINDOW_MS | (env only) | 900000 (15 min) |
DSH_GATEWAY_LOGIN_ACCOUNT_MAX | (env only) | 5 |
DSH_GATEWAY_LOGIN_ACCOUNT_WINDOW_MS | (env only) | 900000 (15 min) |
DSH_GATEWAY_SESSION_IDLE_TTL_MS | (env only) | 28800000 (8 h) |
DSH_GATEWAY_SESSION_ABSOLUTE_TTL_MS | (env only) | 86400000 (24 h) |
DSH_GATEWAY_SESSION_MAX | (env only) | 10000 |
DSH_GATEWAY_AUDIT_RETENTION_DAYS | (env only) | 30 |
DSH_GATEWAY_AUDIT_PURGE_INTERVAL_MS | (env only) | 3600000 (1 h) |
dshgw --host 0.0.0.0 --port 8080 --db ./gw.db --admin-id admin --admin-password secret --pairing-codes 'code1,code2'
dshgw --help # list every flag
Docker-only env vars (no CLI flag): DSH_GATEWAY_BUILD_CMD (default pnpm -r build), DSH_GATEWAY_SRC_DIR (default /app/source), DSH_GATEWAY_PNPM_STORE (default /data/pnpm-store).
Production security checklist:
- Terminate TLS at a reverse proxy and set
DSH_GATEWAY_TRUST_PROXY=1so per-IP login throttling sees the real client; the session cookie getsSecureautomatically overhttps. - Set a strong
DSH_GATEWAY_ADMIN_PASSWORD. On a non-loopback bind orNODE_ENV=production, the gateway refuses to start with the default password unlessDSH_GATEWAY_ALLOW_DEFAULT_ADMIN=1is set explicitly. /nodesrequires a logged-in session (admins see all machines, regular users only their assigned ones);/healthreturns only{ "ok": true }.- Audit retention (ADR-0012):
audit_eventsare auto-purged pastDSH_GATEWAY_AUDIT_RETENTION_DAYS(default 30) by a batched periodic task (DSH_GATEWAY_AUDIT_PURGE_INTERVAL_MS) plus a lazy write-path backstop; set retention to0to disable auto-cleanup. Export the log before that window closes: admins can callGET /gw/audit/export(?format=csv, plus the samesince/until/machineId/actor/action/resultfilters asGET /gw/audit).
Install the agent plugin into a customer machine's dsh (web profile):
# from npm:
dsh plugin --profile web add @januory/dsh-gateway-agent
# or from a local checkout:
dsh plugin --profile web add ./plugins/dsh-gateway-agent
Usage
- Start the gateway (
pnpm --filter @januory/dsh-gateway-server dev) and, optionally, build the portal (pnpm --filter dsh-gateway-web build) so it is served at the gateway root. - Issue a pairing code to onboard:
DSH_GATEWAY_PAIRING_CODES="<code>" pnpm --filter @januory/dsh-gateway-server dev - On the customer machine, install the agent plugin (see Installation), then open the dsh Settings → 网关接入 section, enter the gateway address (
wss://<gateway-host>, path not required) and the pairing code, and click 发起入网申请. - Approve the machine at the gateway, assign it to a user, and open it from the portal — reads and interactions are relayed to that machine's dsh WebUI in real time.
Repository structure
apps/gateway/ # gateway server (control plane + router + API + wss; hosts the portal build)
apps/web/ # portal front end (Vite + React)
packages/protocol/ # shared wire protocol (plain JS, zero build)
packages/store/ # persistence seam (IStore) + domain types
plugins/dsh-gateway-agent/ # customer-machine access plugin (outbound wss bridge to local dsh web)