dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
手机与远程访问 DSH Web 界面:局域网扫码即用,或用自建 relay 中继服务端(替代 cloudflared 隧道)随时随地连回电脑;每台设备独立凭据,可配对、查看与单独撤销;多台电脑共用一个中继并自动热备。
Put DeepSeek Harness in your pocket: scan a QR code on your LAN, or reach it from anywhere through the relay on your own server — with per-device auth and multi-PC coexistence/failover.
Based on shaobeichen/dsh-pocket (GPL-2.0). This fork replaces the cloudflared public tunnel with a self-hosted relay (single Go binary server + web admin), and adds device authentication and multi-PC management.
⭐ A Star would make the author's day · Here, take one
You want to use DeepSeek Harness on your computer, even when you're not at the computer.
That's what DSH Pocket does: install it, scan a QR code, and your phone shows and controls the DeepSeek Harness UI in real time — from anywhere.
What it looks like — the phone shows the exact same UI as your computer, live:
| Feature | Description |
|---|---|
| 📶 LAN QR access | Works out of the box: Settings → Phone access — scan the LAN QR on the same Wi-Fi (auto-detects the LAN IP; under WSL it picks the Windows host's physical NIC IP) |
| 🚪 LAN switch | Turn LAN access off/on with one click in Settings (a confirmation dialog shows each time): off kills the LAN QR code and link instantly; public access is unaffected |
| 🌐 Public QR (from anywhere) | Click "Enable anywhere" → cloudflared tunnel → scan the public QR over 4G / any network |
| 🏷️ Fixed public hostname | Optional "Named tunnel" mode: paste a Cloudflare Tunnel Token + your own domain — the public address stays fixed across restarts (see below) |
| 🔐 Access PIN | Public links require an 8-character PIN (rotated on every tunnel start by default; customizable to a fixed PIN — custom PINs are not rotated); LAN has its own separate 8-character PIN (on by default; switchable off in Settings — then LAN scans connect directly) |
| 🔑 Custom PINs | Both the public and LAN PINs can be set to your own fixed 8-character PIN (letters and digits) in Settings (custom PINs are never auto-rotated) |
| 🧘 Session persistence | Enter the PIN once and you're set for a long time (login is tied to the computer's dsh web process: as long as it stays up, the phone won't ask again; after a dsh web restart/update, enter it once more) |
| ⚡ Real-time sync | Streaming output passes through WebSocket untouched — what the computer renders, the phone renders live; fully interactive both ways; built-in WS heartbeat keep-alive (defeats silent NAT/battery link drops with auto-reconnect) |
| 📱 Mobile-adaptive layout | Narrow screens get a drawer layout automatically (ported from dsh-web-mobile, MIT): sidebar drawer, full-width conversation, safe-area insets, touch optimizations |
| 📁 File browser | The mobile "Files" entries need a host-side explorer panel (a dsh-web-ui component); on stock DSH without it the entries are auto-hidden instead of doing nothing |
| 🗜️ Transfer compression | Large JSON responses are gzip/brotli'd on the fly (17MB session history → ~1MB; brotli quality 6: fast and bandwidth-friendly) — faster loads, less mobile data |
| 🔁 Tunnel auto-restore | After a DSH restart the previously-running public tunnel comes back automatically |
| 🧩 Zero-dependency install | One npm package, one settings tab — no core/adapter split, no account, no server |
Where the entry is: after installing and restarting dsh web, open Settings — the left sidebar shows "Phone access" at the top level (same level as General / Models):
Prerequisite: DeepSeek Harness installed. If your terminal says dsh: command not found, install it first:
npm install -g @deepseek-ai/dsh # global install; verify: dsh --version
# No global install? Prefix every command with: npx @deepseek-ai/dsh
# 1. Install the plugin (everything in one package)
dsh plugin --profile web add dsh-pocket-relay -w
# 2. Restart dsh web
npx @deepseek-ai/dsh web
Settings → Phone access → scan the "📶 LAN" QR code → enter the LAN PIN (shown in the LAN block; hit Refresh to roll a new one, or Customize to set your own fixed 8 digits) → the phone opens the exact same DSH, in real time.
The "LAN access" switch is on by default and can be turned off/on with one click (a confirmation dialog shows each time). Off kills the LAN QR code and link instantly (phones can't open them); public access is unaffected. Tap "On" to restore it.
The LAN PIN is on by default (security-first). If you're the only user and find typing it every time annoying, flip "LAN access PIN" to Off in the LAN block — LAN scans then connect directly with no PIN (LAN-only devices; the public tunnel always requires a PIN, unaffected).
After logging in once, the phone won't ask again: as long as the computer's dsh web keeps running, reopening the phone needs no PIN (a dsh web restart/update asks for it once more).
Advanced option: auto-detection may not pick a reachable address for Tailscale/VPN setups. You can select a detected IP from the "LAN address" dropdown; normally no change is needed.
On the same page click "Enable anywhere" → a security disclaimer pops up every time — check "I understand and agree" to proceed (on a corporate/classified network, confirm compliance first) → wait for the tunnel (first run downloads cloudflared; macOS/Linux use the Tsinghua mirror, seconds) → scan the "🌐 Public" QR code → the phone opens the link and enters the 8-character PIN (shown in the settings page's public section; rotated on every tunnel start by default, or Customize it to a fixed PIN — letters and digits — that is never rotated) → works from outside (4G / office network).
Upgrading:
dsh plugin --profile web update dsh-pocket-relay --latest -w(--latestis required across major versions — a^0.xrange won't auto-jump to 1.x).
The default "quick tunnel" gets a new random URL on every restart. For a fixed public address, use a Cloudflare named tunnel (requires a Cloudflare account + your own domain):
pocket.example.com) to http://127.0.0.1:3081Note: in named-tunnel mode the public PIN is not auto-rotated (the address is fixed, so the PIN stays the same across restarts) — manage it proactively with a custom PIN. The Tunnel Token is stored locally only ($DSH_HOME/dsh-pocket/settings.json, readable by your user only) and is never echoed back in the UI.
$DSH_HOME/dsh-pocket/token (re-rolled per tunnel start unless customized), the LAN PIN in $DSH_HOME/dsh-pocket/token-lan (refreshed manually in Settings), and switches/custom flags in $DSH_HOME/dsh-pocket/settings.json.| Symptom | Cause & fix |
|---|---|
dsh: command not found / "DSH is not defined" | dsh CLI missing: npm install -g @deepseek-ai/dsh, or prefix commands with npx @deepseek-ai/dsh |
ERR_PNPM_ADDING_TO_ROOT | pnpm 9 workspace-root restriction: append -w (--workspace-root) to install/update commands |
| Nothing changed after install/update | You must restart dsh web; the running process still loads the old code |
listen EADDRINUSE ... :3081 | A stale dsh-pocket-relay process holds the port: macOS/Linux lsof -ti :3081 | xargs kill -9; Windows netstat -ano | findstr :3081 (find the LISTENING PID) → taskkill /PID <PID> /F, then retry |
| Want a different port (issue #70) | Plugin mode: write "proxyPort": 3082 into $DSH_HOME/dsh-pocket/settings.json and restart dsh web. CLI mode: dsh-pocket-relay --port 3082. If the port is taken you'll get EADDRINUSE — kill the old process or pick another one |
| Issue a temporary PIN to a guest | Not available: the temporary access PIN feature (issue #69) was removed in 2.6.x (it crashed on revoke). To share access, send the main PIN or a ?token=<main PIN> link, then hit "Refresh" in Settings once the guest is done |
| cloudflared install fails on a remote Linux server (issue #45) | If all CDN sources (GitHub / ghproxy / gh.ddlc / gh-proxy) are unreachable on a remote Linux host, install cloudflared yourself (e.g. apt install cloudflared, dnf install cloudflared, or download the tgz and unpack it), then add "cloudflaredPath": "/path/to/cloudflared" into $DSH_HOME/dsh-pocket/settings.json and restart dsh web. The plugin will then use that binary directly and skip the auto-download |
| Version stuck below 1.x | ^0.x ranges never jump to 1.x: update with --latest (dsh plugin --profile web update dsh-pocket-relay --latest -w) |
Public error 1033 | See "Public tunnel troubleshooting" below — usually a local proxy/VPN (Clash etc. TUN mode) killing the tunnel |
| After "Restart dsh web", the page says the process is running in the background | The new process from in-page self-restart is a detached background process (not attached to your terminal) — that's the standard way to apply updates in-page; stop it: macOS/Linux lsof -ti :3080 | xargs kill -9; Windows netstat -ano | findstr :3080 → taskkill /PID <PID> /F (logs under $DSH_HOME as dsh-pocket-restart-*.log) |
Symptom: after clicking "Enable anywhere", the public URL shows error 1033 (Tunnel error) on the phone.
Most common cause: a local proxy/VPN (Clash, Surge, v2ray, sing-box, etc., especially in TUN mode).
Such tools take over all traffic and often cut cloudflared's tunnel-edge connections
(*.argotunnel.com, Cloudflare edge IPs), so the tunnel registers but the data plane never connects.
Fix (try in order, lightest first):
ps aux | grep clash), then retry.- DOMAIN-SUFFIX,argotunnel.com,DIRECT
- DOMAIN-SUFFIX,trycloudflare.com,DIRECT
- IP-CIDR,198.41.192.0/24,DIRECT,no-resolve
Other causes: corporate firewalls / campus networks blocking outbound — ask IT to allow it, or use a hotspot.
First run: "Downloading cloudflared" fails or hangs:
cloudflared command and retry (the plugin then uses the PATH binary, no download):
brew install cloudflared; Linux: sudo apt install cloudflared or from the official sitewinget install cloudflared or from the official sitenpm i -g cloudflared$DSH_HOME/dsh-pocket/bin/ ($DSH_HOME is usually ~/.dsh, on Windows %USERPROFILE%\.dsh; name it cloudflared (add .exe on Windows) or the release asset name — both are recognized)