DSH prohibits the use of --host 0.0.0.0, which makes it difficult for developers to directly access the DSH web interface locally or over the local network. The dsh-lan-proxy plugin runs inside the DSH process, exposes HTTP/HTTPS listening externally, and forwards requests to DSH’s loopback service. It is a pure ESM plugin, supports dual-stack listening, and can handle TLS certificates and IP allowlists.
Installation¶
Install it using the official plugin command. After installation, restart the DSH process.
# 从 GitHub 安装
dsh plugin --profile web add github:mariGoIds/dsh-lan-proxy#v1.1.0
# 或从本地目录安装
dsh plugin --profile web add file:/path/to/dsh-lan-proxy
Core Features¶
The plugin runs inside the DSH process and listens locally by default. After enabling the configuration, it can expose HTTP/HTTPS forwarding externally. Main features include:
- Dual-stack listening: Listens on IPv4 and IPv6 simultaneously.
- Access control: Supports IP allowlists (prefixes / exact IPs) for passwordless direct access.
- TLS support: The default listening port is 3443. It supports certificates; if a certificate is missing or the port is in use, it only skips the corresponding listener without terminating DSH.
- One-time login code: Generates a login code that can be viewed only locally; it becomes invalid after one use and is suitable for temporary devices such as phones.
- Device management: Assigns an independent token to each device and supports individual revocation and validity control.
- Logging and adaptation: Automatically masks sensitive parameters in logs; fixes the persistence issue of the DSH settings page under a reverse proxy (patchClientBundle).
Configuration¶
Configuration is overridden through cordis.patch.yml. The default security policy is empty (no IP allowlist and no login code).
- id: lan-proxy
config:
listenHost: '::'
httpListenHost: '127.0.0.1'
listenPort: 3080
tlsPort: 3443
backendHost: 127.0.0.1
backendPort: 3081
allowedPrefixes: ['192.0.2.'] # 免密可信网段
allowedIps: [198.51.100.25]
cookieName: dsh_auth
accessLog: true
accessLogFile: '' # '' = 仅进 dsh 日志器;非空则落盘
certDir: '' # '' = $DSH_HOME/certs
forwardUntrusted: false # true = 非白名单放行给 dsh
patchClientBundle: true
autoLogin: 'trusted' # 'off' | 'trusted' | 'always'
codeLogin: false
codeLength: 6
codeLeaseMinutes: 5
codeMaxFails: 5
codeGlobalMaxFails: 20
codeLockMinutes: 10
codeSessionDays: 30
maxDevices: 20
deviceStateFile: '' # '' = $DSH_HOME/lan-proxy-devices.json
Key Configuration Notes¶
listenHost: Binding address;::indicates dual-stack (IPv4 + IPv6).autoLogin: Automatically obtains the DSH web token.'off'does not intervene,'trusted'(default) automatically logs in only for allowlisted sources, and'always'automatically logs in for all sources. When enabling'always', it must be combined with an IP allowlist or login code, otherwise it is equivalent to having no authentication.codeLogin: Enables the one-time login code feature.forwardUntrusted: Determines how sources outside the allowlist are handled.falsereturns 403;trueforwards them to DSH.
Access Decision Logic¶
The plugin determines access permissions in the following order:
- IP allowlist: If the IP is in
allowedPrefixesorallowedIps, allow it directly. - Login code validation: If the IP is not allowlisted and
codeLoginis enabled, check the device session Cookie; if invalid, redirect to the login page. - Trusted forwarding: If the IP is not allowlisted and
codeLoginis disabled, decide based onforwardUntrustedwhether to forward the request to DSH.
One-Time Login Code¶
Non-allowlisted devices (such as phones) can access DSH through a one-time login code. It can be generated at http://127.0.0.1:3080/__lan_code or on the DSH settings page.
The code is numeric and valid only within its lease period, and it must be used together with failure rate limiting. Rate limiting has two levels: codeMaxFails counts per individual IP, while codeGlobalMaxFails counts all sources in total. After the global limit is reached, a global lock is applied and the wait time increases with exponential backoff (capped at 24 hours).
Authorized Devices¶
Each device authorized through a login code holds an independent token, which can be revoked individually on the settings page. The device limit is controlled by maxDevices; when the limit is exceeded, the least recently used device is evicted. The persisted device table stores only the SHA-256 hash of the token, while the plaintext token exists only in the browser Cookie.
Known Limitations and Notes¶
- Version lock: This version is currently compatible only with the DSH developer preview. Please pin the version to
#v1.1.0. - TLS certificate: If using IPv6 listening, the certificate’s SAN (Subject Alternative Name) must include that IPv6 address or domain name; otherwise, the browser will report a name mismatch.
- Bundle patch: It relies on DSH internal implementation details. After a major DSH upgrade, it is recommended to recheck the settings page.
- Log cleanup: Access log files do not have automatic rotation and must be cleaned up periodically by you.
- Security warning: The IP allowlist is a passwordless channel. Do not configure untrusted network segments. Global rate limiting may be abused for DoS attacks, where an attacker can intentionally enter wrong codes to lock out legitimate users.
Summary¶
For developers who need to manage DeepSeek Harness locally or over the local network, this plugin provides a lightweight reverse proxy solution. All configuration is file-based, and uninstalling automatically cleans up the configuration.
- GitHub: https://github.com/mariGoIds/dsh-lan-proxy
- Directory: https://www.skillhub.cn/plugins/mariGoIds/dsh-lan-proxy