Introduction

When deploying dsh web to a server and wanting to use it remotely via a browser, you first encounter a problem: the web application itself has no password verification, so anyone who obtains the address can open it. The harness itself is kept bound to 127.0.0.1 loopback (binding to 0.0.0.0 is prohibited) as per official requirements. The common approach is to set up a layer of authenticated reverse proxy in front of it, but this means maintaining an extra proxy configuration.

The dsh-gateway-plugin introduced below turns this into a DSH plugin: after being installed into a profile, it opens its own gateway port as the sole external entry point. On the gateway port, aside from the login/first-time setup page, there are no unauthenticated accessible content surfaces.

Overview

Maintained by laoin114514, under the MIT license, dsh-gateway-plugin is positioned as a password gateway plugin for DeepSeek Harness Web.

It implements a “password reverse proxy” in plugin form: browsers access the gateway port, and unauthenticated requests are blocked; only authenticated requests are reverse proxied to harness. The gateway rewrites Host/Origin and allows the internal trust boundaries of harness. The entire process requires no changes to the harness itself.

Core Capabilities

  1. Absolute Gatekeeping. On the gateway listening port, only /gateway/login (GET page + POST login/set password) is accessible without authentication; there are no other exceptions: unauthenticated pages and static resources are 302’d to the login page, /api returns 401, and WebSocket upgrades are directly rejected.

  2. First-time Password Setup. When no password has been set, the login page presents a setup form; the first visitor to set it successfully immediately obtains a session; thereafter, everyone uses that password to log in.

  3. Changing Passwords. Performed on a dedicated “Security” page in settings (current password + new password × 2); upon successful modification, all logged-in sessions become invalid immediately (signature key rotation).

  4. Anti-Brute Force. Password comparison is done via SHA-256 first, then timingSafeEqual for constant-time comparison; login failures are rate-limited based on source address, defaulting to a 30-second cooldown after 5 consecutive failures.

  5. Stateless Sessions. Sessions are HMAC-SHA256 signed cookies (HttpOnly, SameSite=Lax), and the signature key is randomly generated at every process startup. Restarting means everyone re-logs in, which is an intentional fail-closed behavior.

  6. Two Authentication Methods. Supports session cookies or request header Authorization: Bearer <password>.

  7. Out of the Box. The build artifacts (lib/) are included in the repository commit. After git installation, there is no need to run build scripts or grant build permissions.

Installation and Usage

Prerequisite: the dsh CLI is installed (or source code is checked out). Execute:

dsh plugin --profile web add github:laoin114514/dsh-gateway

To prevent the repository from silently changing the installed code via subsequent pushes, it is recommended to pin to a specific commit:

dsh plugin --profile web add github:laoin114514/dsh-gateway#<commit-sha>

After installation, start dsh web, and the gateway address will be printed in the logs:

dsh-gateway: http://127.0.0.1:3088 (gateway, password required) -> harness http://127.0.0.1:3080

Following the steps above, note that the gateway address, not the harness address, must be opened from now on. On the first visit, the login page will guide you to set the access password; thereafter, simply enter that password on every visit.

Typical Usage

Exposing to the Network

By default, the gateway only binds to 127.0.0.1. When access from other machines is needed, override gatewayHost for the dsh-gateway line in $DSH_HOME/profiles/web/cordis.patch.yml:

- id: dsh-gateway
  config:
    gatewayHost: '0.0.0.0'

The harness itself remains bound to loopback (officially prohibited from binding to 0.0.0.0), and the gateway is the sole external entry point.

Configurable Options

The gateway provides the following configuration on the dsh-gateway line in cordis.patch.yml:

  • gatewayHost, gatewayPort: Gateway listen address and port;
  • sessionTtlHours: Session validity period;
  • minKeyLength: Minimum password length;
  • maxLoginFailures, loginCooldownSeconds: Rate limiting threshold and cooldown duration for login failures (defaults to 30-second cooldown after 5 consecutive failures);
  • accessKey: Initial password; leave blank to enter first-time setup mode.

Troubleshooting Installation Failures

If dsh plugin add reports an error like ERR_PNPM_ENOENT (common in partially installed directories left by previous failed installations), clean up before reinstalling:

dsh plugin --profile web remove dsh-gateway-plugin
# or manually delete the partially installed directory:
rm -rf "$DSH_HOME/profiles/web/node_modules/dsh-gateway-plugin"
dsh plugin --profile web add github:laoin114514/dsh-gateway

Local Development with Source Checkout

When you need to synchronize with the repository source code, first check out the source, then execute in the repository root:

pnpm dsh web --patch <dsh-gateway>/cordis.dev.yml --no-open --port 3082

Note: When starting with the --patch overlay method, the browser-side “Security” settings page will not load — only profile lines can be discovered by the client module system.

Use Cases and Notes

Suitable scenarios: Deployments where dsh web is running on a server or internal network, accessed via a browser, but without exposing ports openly.

Pay attention to the following points before use:

  • The plugin does not provide TLS. For public network or cross-segment transmission, a terminating reverse proxy for TLS must be placed in front of the gateway, or the network must be restricted to the internal network.
  • Passwords are stored in plaintext in the user settings file (settings namespace dsh-gateway, field accessKey, declared as role('secret'), and will not be carried in any wire responses). Please manage this file with the permissions of a sensitive file.
  • The session signature key is randomly generated at every process startup. After a restart, all sessions become invalid and require re-login; this is an intentional fail-closed behavior.
  • By default, the gateway only binds to 127.0.0.1; the harness itself should maintain loopback binding (binding to 0.0.0.0 is prohibited by official policy).
  • Like installing any DSH plugin, the plugin runs with the permissions of the current dsh process. It is recommended to review the source code and license before installing (this project is MIT).

Summary

With the cost of a single profile installation command, dsh-gateway-plugin guarantees “no unauthenticated content surfaces” on the gateway port: first-time password setup, modification, login rate limiting, and session invalidation strategies are all ready-to-use, allowing the harness itself to remain securely behind the loopback address.

The plugin is listed in the community plugin directory (independent site, no official affiliation with DeepSeek / HF): https://www.skillhub.cn/plugins/laoin114514/dsh-gateway, source code repository: https://github.com/laoin114514/dsh-gateway.