Back to home@januory

deepseek-harness-gateway

No description

Stars
2
Language
TypeScript
Created
Sep 2, 2026
Updated
Sep 7, 2026
GitHub repo

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 /agent and 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 variableCLI flagDefault
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 1off
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=1 so per-IP login throttling sees the real client; the session cookie gets Secure automatically over https.
  • Set a strong DSH_GATEWAY_ADMIN_PASSWORD. On a non-loopback bind or NODE_ENV=production, the gateway refuses to start with the default password unless DSH_GATEWAY_ALLOW_DEFAULT_ADMIN=1 is set explicitly.
  • /nodes requires a logged-in session (admins see all machines, regular users only their assigned ones); /health returns only { "ok": true }.
  • Audit retention (ADR-0012): audit_events are auto-purged past DSH_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 to 0 to disable auto-cleanup. Export the log before that window closes: admins can call GET /gw/audit/export (?format=csv, plus the same since/until/machineId/actor/action/result filters as GET /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

  1. 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.
  2. Issue a pairing code to onboard:
    DSH_GATEWAY_PAIRING_CODES="<code>" pnpm --filter @januory/dsh-gateway-server dev
    
  3. 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 发起入网申请.
  4. 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)