LAN/remote access for the Web UI: injects a crypto.randomUUID polyfill on plain-HTTP origins so the frontend survives LAN or Tailscale IP direct links.
Install
# from npm (prebuilt)
dsh plugin --profile web add dsh-web-lan-access
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:AcidGr/dsh-web-lan-access
Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).
README
English | 简体中文
LAN / remote access support for the DeepSeek Harness Web UI.
The problem
The Web UI calls crypto.randomUUID() in boot-critical paths (RPC id minting, message ids, draft attachments). That Web API exists only in secure contexts (HTTPS, or http://localhost / http://127.0.0.1). When the UI is served over plain HTTP from a non-loopback address — a LAN IP, a Tailscale IP, or a hostname — crypto.randomUUID is undefined, every RPC throws, and sessions and models never render.
Current DSH clients also select Host-backed settings from the browser hostname: a non-loopback page is assigned memory-only settings even after browser authentication succeeds. The Models and plugin settings pages therefore remain unavailable on an otherwise working trusted-host deployment.
The fix
A host-side plugin that uses the webserver's official index-tap extension point (webServer.tapIndex) to inject a small bootstrap as the first script in <head>, before the boot manifest and shell entry. The bootstrap:
- supplies an ordinary HTTP transport carrying DSH's
ownsHostdeployment signal, enabling authenticated Host settings from the trusted remote page; - polyfills
crypto.randomUUIDwith an RFC 4122 v4 implementation built oncrypto.getRandomValues, which is available on insecure origins.
The bootstrap leaves a transport supplied by another shell untouched, and the UUID polyfill is a no-op on secure origins.
- No product source modified; fully reversible
- Uses DSH's existing index-tap and client-transport extension points
- Platform-independent (Linux / macOS / Windows / Android)
Install
Method 1: Ask your DSH Agent (Easiest 🤖)
Send this repo URL directly to your DSH chat with the instruction:
"Install this plugin for me: https://github.com/AcidGr/dsh-web-lan-access"
Your DSH Agent will automatically install the package and configure it in the background.
Method 2: Bundle install via CLI (Recommended)
Installed from npm:
dsh plugin --profile web add dsh-web-lan-access
(No npm / local development — point pnpm at the repo instead:
dsh plugin --profile web add github:AcidGr/dsh-web-lan-access
)
Restart dsh web, then hard-refresh the browser.
Method 3: Manual install (no pnpm / offline)
PROFILE="$DSH_HOME/profiles/web" # adjust DSH_HOME and profile name
mkdir -p "$PROFILE/plugins" "$PROFILE/node_modules/@dsh-profile"
cp -r dsh-web-lan-access "$PROFILE/plugins/lan-access"
ln -sfn ../../plugins/lan-access "$PROFILE/node_modules/@dsh-profile/lan-access"
# append to $PROFILE/cordis.patch.yml:
# - insert:
# - id: lan-access
# name: '@dsh-profile/lan-access'
Usage
The plugin is self-contained: its bundle patch sets the webserver bind host to 0.0.0.0 directly (the CLI flag --host 0.0.0.0 is hard-rejected for safety on newer harness versions, but the webserver config still accepts it — so no source changes and no --host flag are needed; the CLI --port flag still works). It also widens the /api trust fence automatically.
Install the plugin, then start normally — without
--host:dsh --profile web --port 3080The bundle patch re-derives the
/apitrust fence from every non-internal IPv4 the host currently has — LAN (192.168.x), Tailscale (100.x), and VPN interfaces — and merges in whateverresolveLanTrustalready computed. So as long as the remote interface is up whendsh webstarts (Tailscale usually autostarts first), LAN and Tailscale IP access need zero extra config: openhttp://<server-ip>:3080orhttp://<tailscale-ip>:3080and sessions/models load.If you prefer NOT to let the plugin take over the bind host (e.g. you want loopback + a port forward), keep the
webserverrow override out of your tree and instead forward a port (socat / rinetd / Tailscale serve) from127.0.0.1:3080, adding the forwarded address totrustedHostsmanually.MagicDNS hostnames (e.g.
xxx.tailXXXX.ts.net) — the fence can't discover hostnames, only IP literals, so add your own names if you want to browse by name instead of IP. Patch theweb-runtimerow, whosetrustedHostsfeed into the fence computation (resolveLanTrustmerges them), so your entries stack on top of the auto-discovered IPs:- id: web-runtime config: trustedHosts: - <short-name> # e.g. myhost — MUST be listed separately! - <name>.tailXXXX.ts.net # full domainOr skip file editing entirely with the repeatable CLI flag (same injection path):
dsh --profile web --trusted-host myhost --trusted-host myhost.tailXXXX.ts.net. Use one mechanism or the other — a static list replaces the row's default expression, so it will not merge with--trusted-host.⚠️ The fence compares the
Hostheader literally: a MagicDNS short name (http://myhost:3080) is not the full domain — list the short name on its own line, or every/apicall returns 403 (page shell loads, sessions/models absent). Tailscale / LAN IP literals need no entry here — they stay covered automatically.⚠️ Do not retarget this block at the
connectionrow: patch layers compose by whole-key replacement in application order (bundle layers first, then your profile'scordis.patch.yml), so a plain literal array onconnection.config.trustedHostswould silently replace the bundle's dynamic fence expression — names would work, but the auto-derived LAN/Tailscale IP trust would vanish. If you truly needconnection, copy the full concatenation expression from the plugin's bundle patch and append your literals; never write a plain list there.
Host ownership scope
The transport signal enables every client surface DSH currently associates with owning the Host, not only Models. That includes Host-backed settings and native Host actions such as opening a produced file. Use this plugin only when the authenticated remote browser is meant to operate the agent machine. DSH's Host/Origin fence and browser authentication remain in force; this signal changes the client's capability projection, not request authentication.
Older harness builds that pin privileged methods to loopback on the server will continue returning 403 for those methods. This client bootstrap does not weaken that server-side fence.
Verify
curl http://127.0.0.1:3080/ | grep lan-access-polyfill # must match
Then open http://<server-ip>:3080 from another device — sessions and models must load.
Security warning
Binding 0.0.0.0 exposes the DSH authentication surface to every reachable interface. trustedHosts is an Origin/Host fence, not identity; current DSH builds separately authenticate the browser. Use only on trusted networks, restrict with a firewall (e.g. ufw allow from 192.168.0.0/16), or expose through Tailscale or an authenticated reverse proxy. A TLS reverse proxy removes the need for the UUID polyfill but not the remote Host-settings bootstrap.
Rollback
- Bundle install:
dsh plugin --profile web remove dsh-web-lan-access - Manual install: delete the
lan-accessinsert block fromcordis.patch.yml; optionally start without--host 0.0.0.0
License
MIT
Links
More in this category
zhu1090093659/dsh-web#packages/dsh-remote-web-ui★ 8076
Remote control of a dsh web workspace from phone or PC: QR-code pairing through a token-gated channel, SSE real-time sync, and separate mobile and full desktop GUI modes.
zhu1090093659/dsh-web#packages/dsh-ssh★ 8076
SSH ops panel for DSH: web terminal, SFTP transfer with progress, local port forwarding, and one-command cluster execution across hosts; agents share the same host config.
saya-ch/dsh-mobile★ 325
Access DeepSeek Harness from the Android app or a mobile browser with secure LAN and remote connections, persistent device pairing, and a customizable mobile interface.
ZSeven-W/dsh-ios★ 308
A live iOS Simulator or USB-connected iPhone inside the conversation: 22 agent tools for booting, building, driving the UI by accessibility identity or OCR text, list-row actions and SwiftUI preview hot reload, plus a streaming sidebar panel you can tap and drag on.
liguobao/ds-harness-remote★ 225
Multi-device remote access for DeepSeek Harness: continue an active session from your phone, tablet, browser, or another computer over an end-to-end encrypted channel (Noise IK + adaptive relay/WebRTC transport), with device authorization, ApiProxy-only remote capabilities, and read-only file preview via dsh-file-viewer — no shell, remote desktop, or write access.
wenbin-wb/dsh-bridge★ 177
Remote and mobile access for DeepSeek Harness: provides LAN QR code connection, Cloudflare/custom tunnels, WeChat, QQ, Feishu, Telegram bot integration, and security authentication.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.