DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

Lan Guard — DSH Plugin for DeepSeek Harness
← Plugins
L

dsh-lan-guard

Lan Guard

DSH web plugin: expose the official desktop Web UI to the local network through a gated reverse proxy, without touching DSH's own loopback binding.

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add github:idoall/dsh-lan-guard#9c68de20257cd991b34ea15e38e7349a336ba165
READMECompatibilityVersions
Settings → 局域网访问 → 扫码访问: running state, passwordless link and a scannable QR codeConnection & certificates: the listen-scope switch between LAN (default) and this-machine-only, the proxy port with its availability check, and NIC selection
Authentication: the three-way mode selector, access and admin password fields, and the loopback-exempt switch
Authorised devices: naming and admin-approval switches, plus the device list with revoke-and-block
The official DSH UI at a 390px phone viewport: the plugin only proxies, the interface is the official one

Compatibility and provenance

Lan Guard is published as dsh-lan-guard and currently resolves to version 0.3.2. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
web
Release source
github
Registry updated
9/25/2026

Versions

0.3.2stable
9/25/2026
0.3.1stable
9/25/2026
0.2.0stable
9/25/2026
Show 2 more versionsCollapse versions
0.1.1stable
9/24/2026
0.1.0stable
9/24/2026

Related plugins

Loading related plugins…

Latest
0.3.2
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
Unavailable
Files
Unavailable
Surface
web
License
MIT
Source
github
GitHub
★ 0
Weekly downloads
0
Last push
9/25/2026
View source ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue
DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in

Related plugins

More verified plugins in security-access.

Doctor@linxin666/dsh-doctorTransactional rescue mode for DSH profiles with a supervised launcher, isolated recovery capsule, deterministic repairs, health monitoring, and a local Web recovery consoleDSCODE@toddzheng024/dscode-bundleA complete DeepSeek coding agent with persistent shell, Ultra collaboration and automatic permission review.Auto Reviewdsh-auto-reviewSecond-model AI auto-review for DeepSeek Harness approval requests: a read-only reviewer subagent decides allow/deny on the approval answerer chain, with fail-closed fallback and full session-log audit.Codex Subscriptiondsh-codex-subscriptionUse ChatGPT and Codex subscriptions in DeepSeek Harness with OAuth, quota, safe resets, web search, images, and Fast mode

README

DSH LAN Guard

Expose the desktop DSH Web UI to your LAN safely: a gated reverse proxy with self-signed HTTPS by default and a QR code to open it on a phone. DSH's own loopback binding and the official UI stay untouched.

English | 中文

What it does · Quick start · Settings · Compatibility · Security boundary · Troubleshooting · Changelog

DSH LAN Guard is a DeepSeek Harness community plugin. It registers one section in the official settings page (settings.section), replaces no official layout, and modifies neither DSH source nor DSH's own listen binding.

DSH serves its Web UI on 127.0.0.1 only, and it deliberately refuses to bind 0.0.0.0. This plugin leaves that binding alone and opens a second, gated listener on another port, proxying the official UI outward as-is: a password gate, self-signed HTTPS by default, a QR code to open it on a phone, and device pairing you can approve or block one by one. One restart after install is all it takes — no hand-written configuration.

Settings → 局域网访问 → 扫码访问: running state, passwordless link and a scannable QR code

What it does

  • Gated reverse proxy — relays HTTP and WebSocket end to end (including the official UI's /api/remote.mux long connection), rewrites Host/Origin, strips hop-by-hop headers, and answers 502 when the upstream is down. DSH's own binding and configuration are never touched.
  • LAN-ready by default, but reachable is not the same as enterable — it binds 0.0.0.0, so one restart after install is enough. The gate is on by default and refuses every device until you set an access password, and TLS is self-signed by default — nothing travels in clear. Switch to "this machine only" in the settings page if you prefer.
  • Two passwords — PBKDF2-SHA256 (600,000 iterations). The access password logs visitor devices in; the admin password unlocks this settings page's management console (it falls back to the access password). Plus a dsh_ passwordless link, persistent visitor sessions, per-IP lockout and CSRF checks.
  • Self-signed HTTPS by default, with a stable CA — generates a DSH LAN Guard CA and signs a leaf certificate for the current NIC addresses. Changing IP only re-signs the leaf, so each device trusts the CA once.
  • Your own machine is never locked — direct 127.0.0.1 access is physically unlocked (whoever can use this computer could change these settings anyway). Remote access follows adminPolicy: read-only (default), password-unlocked, or open.
  • Device pairing and permanent blocking — a phone names itself once when it first passes the gate, receives an HttpOnly device-identity cookie, and appears under 已授权设备 (name / created / last used / source IP) where you can revoke and block it. Blocking does not rely on device fingerprinting: re-pairing with the access password from another browser is refused too, and unblocking is the only way back.
  • Settings inside the official page — the "局域网访问" section has four tabs: QR access, authentication, authorised devices, and connection & certificates. All typography and colours use the official design tokens; no official layout is replaced.
  • Configurable port and listen scope — defaults to 3081 (DSH's port + 1) and walks up to ten ports when that one is taken, with an availability check in the settings page. The listen scope toggles between "LAN (default)" and "this machine only"; both need a DSH restart.
  • Optional mDNS — off by default; advertises _dsh-lan-guard._tcp when enabled.
  • Update check — the settings page shows "current version → latest on npm" with a copyable upgrade command. The plugin never installs or restarts anything itself.

Quick start

Requirements:

  • DeepSeek Harness with a Web profile
  • Node.js 20 or newer
  • Verified DeepSeek Harness: 0.1.7-rc.2

Install from npm:

dsh plugin --profile web add dsh-lan-guard@latest

Install from GitHub:

dsh plugin --profile web add "github:idoall/dsh-lan-guard"

Install from a local clone:

git clone https://github.com/idoall/dsh-lan-guard.git
cd dsh-lan-guard
pnpm install && pnpm run build
dsh plugin --profile web add "link:$(pwd)"

Then restart DSH once and open Settings → 局域网访问. After that restart the plugin is already listening on the LAN (default 0.0.0.0:3081, self-signed HTTPS + gate); all you do is:

  1. Set an access password (at least 8 characters) under 安全认证. Until you do, the gate refuses every device.
  2. Check the listen scope under 连接与证书 (LAN by default) and pick the NIC to publish on — the NIC decides which IP the QR code / access URL uses and which addresses the self-signed certificate covers.
  3. Scan the QR under 扫码访问, trust DSH LAN Guard CA once on the phone, enter the access password, and name the device. The phone then runs the official DSH UI.

Remote devices are read-only by default (adminPolicy: local_only): they can use DSH but cannot change plugin settings. Switch the policy on the desktop if you want a phone to manage them.

Settings

Everything lives under Settings → 局域网访问, in four tabs. The non-sensitive switches (enabled, listenPort, listenHost, networkInterface, auth.mode, auth.adminPolicy, auth.adminProtection, auth.allowLoopback, auth.requirePairing, auth.requireApproval) are editable directly; listenPort and listenHost take effect on the next DSH restart; dataDir and tls.* are startup fields that need a profile-patch edit.

SettingDefaultEffect
Listen scopeLAN 0.0.0.0Whether the LAN can reach the port. "This machine only 127.0.0.1" is more conservative; needs a DSH restart. Both choices keep the gate and self-signed HTTPS in force.
Proxy port3081DSH's port + 1; walks up to ten ports when taken, with an availability check. Needs a DSH restart.
NIC to publish onautomaticDecides which IP the QR code / access URL uses and which addresses the certificate covers; virtual NICs are de-prioritised and labelled.
Auth modepasswordless QR + passwordAlso "password only" or "secure token only". Switching revokes every existing visitor session.
Access passwordunsetThe login password for visitor devices. While unset, the gate refuses every device.
Admin passwordunsetUnlocks this settings page's management console; falls back to the access password.
Loopback exemptonDirect 127.0.0.1 access skips the gate (physically unlocked).
Require namingonA new device must name itself once before it appears in the device list.
Require approvaloffWhen on, a named device still needs your 批准 before it is let in.
TLSself-signed HTTPSTurning it off sends the gate password in clear; a non-loopback bind with TLS off is refused at startup unless you set tls.allowInsecureLan: true.

Connection & certificates: the listen-scope switch between LAN (default) and this-machine-only, the proxy port with its availability check, and NIC selection

The plugin reads its config from its Cordis entry. Every key has a usable default, so a fresh install works as-is:

# ~/.dsh/profiles/web/cordis.patch.yml (optional: write only what you want to change)
- id: dsh-lan-guard
  config:
    listenHost: 0.0.0.0              # LAN-facing by default; '127.0.0.1' = this machine only, or one NIC IP
    listenPort: 3081                 # DSH port + 1; auto-walks up to 10 ports when taken
    networkInterface: en0            # optional: publish on one NIC (empty = automatic)
    dataDir: ~/.dsh/profiles/web/data/dsh-lan-guard   # optional; this is the derived default
    tls:
      mode: self-signed              # 'self-signed' (default) | 'provided' | 'off'
      allowInsecureLan: false        # required acknowledgement for LAN plain HTTP
    mdns:
      enabled: false                 # advertise _dsh-lan-guard._tcp
    auth:
      mode: token_and_password       # 'token_and_password' | 'password' | 'token'
      adminPolicy: local_only        # 'local_only' (default) | 'password_unlock' | 'open'
      adminProtection: true          # admin console needs the admin password
      allowLoopback: true            # 127.0.0.1 visitors skip the gate (physically unlocked)
      requirePairing: true           # new remote devices must name themselves once

dataDir is the only key that needs explaining: omit it and the plugin uses <active profile>/data/dsh-lan-guard (e.g. ~/.dsh/profiles/web/data/dsh-lan-guard); set it and your value wins (a leading ~ is expanded). It only decides where the plugin's private state (password hashes, device-token hashes, sessions, self-signed CA) lives — never whether the plugin works.

Authentication: the three-way mode selector, access and admin password fields, and the loopback-exempt switch

Authorised devices: naming and admin-approval switches, plus the device list with revoke-and-block

Compatibility

Current version: plugin 0.3.2, verified on DeepSeek Harness 0.1.7-rc.2.

PluginVerified DeepSeek HarnessWhat this version is
0.3.20.1.7-rc.2, 0.1.7-rc.1Install and go: LAN-facing default + derived dataDir; Liquid Glass settings page at official sizes; single-line scrolling access URL
0.3.10.1.7-rc.2, 0.1.7-rc.1Verification release for 0.1.7-rc.2: no code change, only compatibility metadata
0.3.00.1.7-rc.1Device approval and permanent blocking; fixed the blank page when opening a shared ?auth= link
0.2.00.1.7-rc.1Update check; removed the corner status pill; spacing fixes
0.1.10.1.7-rc.1Documentation release: bilingual user READMEs
0.1.00.1.7-rc.1First release: gated reverse proxy, self-signed HTTPS, device pairing, settings page, QR access
  • Declared range >=0.1.7-rc.1 <0.2.0 (dsh.engines.dsh); DSH versions not listed are unverified — verify them yourself before use.
  • Host/client interfaces this plugin uses: webServer.register / indexTaps, connection.requestRejection, connection.authenticatedUrl, the additive settings.section seat, @deepseek-ai/schemastery, and profileContext (for deriving the default data directory).
  • Breaking default change (from 0.3.2): listenHost now defaults to 0.0.0.0 instead of 127.0.0.1, so one restart after install is enough; 0.3.1 and earlier default to loopback only. The gate and self-signed TLS defaults are unchanged (with no password the gate still refuses every device). See the CHANGELOG.

The official UI is reused with zero modifications and adapts on a phone viewport:

The official DSH UI at a 390px phone viewport: the plugin only proxies, the interface is the official one

Security boundary

  • DSH's own listen address is never changed; the plugin modifies no DSH configuration, session data, or official UI.
  • Gate before listener — the listener only opens after the gate object is constructed. The LAN-facing default is acceptable precisely because auth.enabled defaults to true, the gate refuses every non-loopback device while no access password is set, and TLS defaults to self-signed. All three must hold together.
  • Secrets (secrets.json, devices.json, sessions) live in dataDir with mode 600; passwords are stored only as PBKDF2-SHA256 hashes, a device token is returned in plaintext once and only its SHA-256 hash is stored, and the passwordless-link token is never written to logs.
  • The proxy stamps every forwarded request with an unforgeable source marker so the host can tell "the machine's own operator" from "a visitor through the proxy".
  • Loopback access is physically unlocked by design — whoever can use this computer could change these settings anyway.
  • The access password is shared: revoking a device invalidates that device's identity cookie immediately, but the same browser can re-pair with the password. Permanently blocking one machine would need device fingerprinting or per-device tokens, which this project deliberately avoids.
  • LAN only: no public tunnels, no IM bots, no port forwarding.
  • The plugin installs, restarts and pushes nothing: you copy and run the upgrade command yourself.

Troubleshooting

The phone says the certificate is not trusted. The CA is self-signed: install/trust DSH LAN Guard CA once per device. Compare the SHA-256 fingerprint shown under 连接与证书 first.

The phone cannot connect at all. Confirm both devices are on the same network and that the address matches the QR code, check for a VPN or a "private relay"-style feature intercepting traffic, and make sure the listen scope was not switched to "this machine only".

The settings page says the port is open to the LAN but no access password is set. That is the expected intermediate state: the port is reachable, but the gate refuses every device and leaks nothing. Set an access password under 安全认证.

"Configured port X was taken; switched to Y." Another program holds the port and the plugin walked forward. Change the port under 连接与证书 (with an availability check) or free it.

"This device's access was removed" (403). The device was revoked or blocked under 已授权设备. Delete the record to let it pair again (a blocked device needs 解除拉黑 first).

I forgot the access password. On the machine that runs DSH, open http://127.0.0.1:3080 (direct loopback access is physically unlocked) and set a new one. On a headless server, delete secrets.json in dataDir and set a new password — until then the gate refuses every device.

Every device needs the password again after I changed it. That is intentional: changing the access password or switching the auth mode revokes every existing visitor session.

Plain HTTP on the LAN is refused. A non-loopback listenHost with tls.mode: 'off' is rejected unless you set tls.allowInsecureLan: true — the gate password would otherwise travel in clear text.

Upgrade

The settings page shows "current version → latest on npm" with a copyable upgrade command:

dsh plugin --profile web add dsh-lan-guard@latest

The plugin installs nothing and restarts nothing — you run the command and then restart DSH once. The check only queries the public npm registry and caches results for six hours; when it cannot reach the registry it says so in the UI and leaves the gate and proxy untouched.

Uninstall

dsh plugin --profile web remove dsh-lan-guard
rm -rf ~/.dsh/profiles/web/data/dsh-lan-guard   # optional: removes secrets, device records and the CA

Development

pnpm install
pnpm test          # unit + integration tests (includes type checking)
pnpm run build     # bundles lib/index.js and lib/client.js
pnpm run verify    # typecheck + tests + build + pack dry-run

The client half registers into the official additive settings.section seat; the host half mounts through the package's own cordis.patch.yml.

Release

Releases are tag-driven. Update package.json, move the matching CHANGELOG section out of Unreleased, write release-notes/v<version>.md with both language anchors, then push the release commit and tag:

git tag v0.3.1
git push origin v0.3.1

The release workflow checks that the tag matches the package.json version and that the notes carry both anchors, then runs pnpm run verify, packs the plugin, publishes through npm trusted publishing (OIDC), and creates a GitHub Release with the tarball attached.

License

MIT