DSH HUB
HomePlugin StoreRankingsPublish Guide
Plugin source
Back to catalog

JUANWANG-BUAA /

dsh-full-remote

Verified

DeepSeek Harness plugin for remote access: a token-gated reverse proxy keeps settings, credentials, and file access working over public tunnels and on other devices instead of returning 403. Per-device sessions. 支持通过公网隧道或局域网,在手机等设备上远程使用 DeepSeek Harness,设置、凭据与文件访问等功能保持可用。

★ 11 Stars1 Forks6 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@88a34f79

dsh-full-remote

Awesome dsh-plugin npm CI License: MIT GitHub Repo stars GitHub last commit Node DeepSeek Harness PRs Welcome

Listed in awesome-dsh-plugin · DeepSeek Harness plugin

English | 中文

dsh-full-remote is a plugin for DeepSeek Harness. It places an authenticated reverse proxy in front of the Harness Web server, so the Web UI can be used through a public tunnel or from a device on the local network while privileged APIs such as settings, credentials, and directory browsing remain available.

Desktop control panel Mobile workspace
Desktop control panel Mobile workspace

Problem

DeepSeek Harness binds its Web server to a loopback address and only accepts privileged requests when the Host and Origin headers refer to a loopback address. When the UI is reached through a generic tunnel, these headers carry the public hostname and the trust check fails. The page loads, but the following methods return 403:

  • settings.*
  • credentials.*
  • host.listDirectory
Approach Result
Generic tunnel (SSH port forward, Caddy, binding 0.0.0.0) Page loads; settings.* / credentials.* / host.listDirectory return 403
LAN-only plugin without authentication Usable on the local network; not suitable for public exposure
Password prompt without header rewriting Requests are authenticated, but the privileged APIs remain blocked

Solution

The plugin inserts a reverse proxy between the tunnel and the Harness Web server. The proxy:

  • rewrites Host and Origin to 127.0.0.1 before forwarding, so the privileged APIs pass Harness's trust check;
  • requires an access token or a valid device session before any request is forwarded;
  • forwards HTTP, SSE, and WebSocket traffic;
  • provides a settings page (Settings → Reverse proxy) for starting and stopping the proxy, changing the listen address, rotating the token, and managing device sessions.

Because the rewrite disables Harness's original trust check for remote clients, the plugin provides its own access-control layer in its place. This layer is described under Security model.

The plugin does not manage tunnels. Any tunnel (cloudflared, ngrok, frp, SSH, Tailscale) can be pointed at the local endpoint the plugin publishes.

How it works

flowchart LR
    A[Phone or remote browser] --> B[Public tunnel<br>cloudflared / ngrok / frp / SSH]
    B --> C[dsh-full-remote<br>127.0.0.1:3081<br>authentication + header rewrite]
    C --> D[DeepSeek Harness Web<br>127.0.0.1:3080]
  1. The remote browser connects to the public tunnel, which forwards to the plugin's listener (127.0.0.1:3081 by default).
  2. A request is accepted only with an access token, a valid one-time invite, or an existing device session. Requests that fail authentication do not reach the backend.
  3. The proxy rewrites Host/Origin to loopback, removes untrusted headers, and forwards the request to the Harness Web server at 127.0.0.1:3080.

Features

Privileged APIs

  • settings.describe / update / replace / mutate
  • credentials.describe / set / unset
  • host.listDirectory / pickDirectory / openPath
  • agentPreset.*, llm.discoverModels

Access control

  • 192-bit access token, stored in a state file with mode 0600; reveal and rotation are performed from the local panel
  • Per-device sessions: each login creates an independent device credential, and only a hash is persisted. Devices can be renamed or revoked from the panel.
  • Optional first-visit approval: a new device waits on a page until it is approved from the local panel
  • Phone invite: a QR code or a one-time link (single use, 15-minute expiry). The link does not contain the standing token.
  • Fixed delay and per-IP lockout on failed logins
  • Optional CIDR allowlist for remote IPs
  • Optional trustForwardedFor to use real client IPs from a trusted local tunnel in CIDR / rate-limit / audit, preferring CF-Connecting-IP and otherwise using the rightmost X-Forwarded-For value

Operation

  • Fence self-check: probes settings.describe with the same Host/Origin rewrite the proxy uses
  • Structured JSONL audit log (login, approval, revocation, token rotation, start, stop, WebSocket open/deny/reject) with an in-panel viewer for recent events and JSON export
  • Runtime listen-address changes with automatic rollback when a bind fails
  • Optional local TLS (tlsCertFile / tlsKeyFile)
  • Health endpoint at /_dsh_reverse_proxy/healthz
  • WebSocket upgrade rate limiting: repeated failed upgrades are locked out per remote IP
  • Stream-level request body limit; hop-by-hop and spoofable headers are stripped; upstream set-cookie is removed

Mobile use

  • Settings edits persist when the page is opened through a tunnel hostname
  • Add workspace uses the in-app directory browser; no native dialog appears on the host display
  • For a phone-friendly layout (full-width session area, directory drawer, adapted dialogs), pair it with a mobile-layout plugin such as dsh-web-mobile

Requirements

  • Node.js ^22.19.0 || >=24
  • A DeepSeek Harness web profile. The plugin depends on webServer and is not intended for headless profiles.

Installation

dsh plugin --profile web add dsh-full-remote
dsh --profile web
  1. Open http://127.0.0.1:3080.
  2. Open Settings → Reverse proxy (last entry in the left navigation).
  3. Press Start proxy and copy the local target.
  4. Point the tunnel at the target:
# Examples only. The plugin does not execute these commands.
cloudflared tunnel --url http://127.0.0.1:3081
ngrok http 3081

For devices on the same network, set the listen address to a LAN IP instead of using a tunnel.

The package was previously published as dsh-reverse-proxy.

Usage

Starting and stopping

On the settings page, press Start proxy to start the listener and Stop proxy to stop it.

Listen address

Bind Purpose
127.0.0.1 (default) The tunnel runs on the same machine
192.168.x.x A device on the same network, without a tunnel
0.0.0.0 / :: Bind every interface. This is not an address to open; the panel reports a separate reachable address.

The listen address can be changed at runtime and persists across restarts. If a new address fails to bind, the proxy rolls back to the previous working address.

The copyable tunnel target (and any extra reachable URL the panel lists) is what a remote client should open. Binding 0.0.0.0 only listens; it is not a URL.

backendHost is the address the proxy connects to, not the address it listens on. Keep it at 127.0.0.1.

Phone invite

The QR encodes a one-time login URL. Public / reachable Origin is the host the scanning device will request: the tunnel's https://…, or the LAN URL from the panel. Leave it empty only when the tunnel target above is already that address.

Do not put 127.0.0.1 in Origin. That address is the Harness machine; a phone would open its own loopback and never reach the proxy.

Then press Generate invite. After a scan (or opening the link) the login page submits once. The invite expires in 15 minutes, works once, and does not contain the standing token.

Upgrade

dsh plugin forwards to pnpm. If you installed with an exact pin such as add dsh-full-remote@0.2.4, a bare update dsh-full-remote reports Already up to date and stays on the old version. To jump to the latest npm release:

dsh plugin --profile web update --latest dsh-full-remote

Then restart dsh web. --latest ignores the current range, installs the newest version, and rewrites package.json. For a specific version use dsh plugin --profile web update dsh-full-remote@0.2.5.

Screenshots

Desktop

Control panel Fence self-check
Control panel Fence self-check
Phone invite (QR) Access token Listen address
Phone invite Access token Listen address

Mobile

Login page (phone) Add workspace on phone Mobile control panel
Mobile login Mobile workspace Mobile panel

Configuration

Common options:

- id: reverse-proxy
  name: dsh-full-remote
  config:
    listenHost: 127.0.0.1
    listenPort: 3081
    approvalMode: false          # true: approve each new device locally
    allowedCidrs: []             # e.g. ["192.168.1.0/24"]; empty: any IP after login
    trustForwardedFor: false     # true: trust CF-Connecting-IP / rightmost X-Forwarded-For from a trusted local tunnel
    upgradeMaxAttempts: 10       # failed WebSocket upgrades before lockout
    upgradeLockoutSeconds: 300   # lockout for repeated failed WebSocket upgrades
    headersTimeoutMs: 15000      # timeout for request headers
    requestTimeoutMs: 120000     # timeout for the complete request; effective value is >= headersTimeoutMs
    sessionIdleSeconds: 0        # 0: off; otherwise idle timeout in seconds
    auditLog: true
    allowTokenRead: true         # false: token only returned on rotation
    tlsCertFile: ""              # optional local HTTPS
    tlsKeyFile: ""

The complete option list, with defaults and validation, is defined in the package Config schema (src/index.ts).

Two points to note:

  • Installing the plugin pins the in-app directory picker so that a phone can add workspaces. Do not re-enable the stock directory-picker row in the same profile.
  • backendHost must remain a loopback address. A wildcard or non-loopback value is rejected at load time.

Security model

The Host/Origin rewrite restores the privileged APIs and, at the same time, disables Harness's original protection for remote clients. The access-control layer provided by this plugin consists of:

  • a 192-bit access token, stored locally with file mode 0600;
  • an HttpOnly, SameSite=Strict session cookie per device, carrying a per-device secret of which only a hash is stored;
  • a fixed delay plus a per-IP 429 lockout on failed logins;
  • loopback-only control routes (/dsh-reverse-proxy/*), which require a control header and are never forwarded through the public proxy;
  • removal of spoofable forwarding and hop-by-hop headers, so the proxy's own cookie never reaches the backend;
  • optional trustForwardedFor: when enabled, only a loopback peer's forwarding headers are trusted for CIDR / rate-limit / audit, so a local tunnel can see real client IPs. It prefers CF-Connecting-IP and otherwise uses the rightmost X-Forwarded-For value to avoid client-side spoofing. Keep it disabled for direct LAN access.

The access token must be treated as a secret. Terminate TLS on the public side of the tunnel. For LAN use without a tunnel, set tlsCertFile / tlsKeyFile (for example with mkcert).

Limitations

  • Control actions (start, stop, reveal token, change listen address) can only be performed from the local Harness window, not from the tunnel URL.
  • Settings persistence on a remote page relies on a temporary trust pin until Harness provides a proper deployment trust field. "Open on host" from a phone acts on the machine running Harness.
  • With allowTokenRead: true (the default), GET /token is served over loopback HTTP, so any local process that sends the control header can read the token. Set allowTokenRead: false to receive the token only when rotating.
  • By default, a tunnel running on the same machine makes every remote client appear as 127.0.0.1 to the proxy. allowedCidrs and per-IP login lockout therefore apply to the tunnel as a whole unless trustForwardedFor: true is set behind a trusted local edge.
  • The plugin replaces Harness's remote trust check with its own access-control layer. A defect in this layer has serious consequences. If Harness provides official remote access in the future, the role of this plugin should be reassessed.

Development

Build from source

pnpm pack
dsh plugin --profile web add ./dsh-full-remote-0.2.5.tgz

Git installs run the prepare build. On pnpm ≥ 10 allow it:

allowBuilds:
  dsh-full-remote: true

Checks and CI

pnpm install
pnpm run check:ci

check:ci runs lint, typecheck, unit and client tests, and a build. CI adds a real dsh plugin add smoke test against a live Harness composition. .github/workflows/canary.yml runs a weekly smoke test against the harness default-branch tip.

The loopback control API lives at /dsh-reverse-proxy/* and is never forwarded through the public proxy. The settings page is the intended interface; the raw routes are rarely needed. For example, recent audit events can be read with GET /dsh-reverse-proxy/audit?limit=50&event=login.ok from the local control surface.

Contributing · Security · License

  • CONTRIBUTING.md
  • SECURITY.md
  • MIT © 2026 JUANWANG-BUAA
DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

APIPublish GuideAbout
—/ 5

No ratings yet

Verified DSH bundle

Commit 88a34f79f9ce

Community comments

No comments yet. Be the first to write one.