
dsh-relay
Use your DeepSeek Harness from your phone without opening it up to everyone on your Wi-Fi.
dsh-relay is a plugin for the harness's web profile. It puts HTTPS, a password, and device pairing in front of the harness, so you can reach it from another device on your network, or from anywhere if you forward a port.
It's built on DeepSeek Harness, but it isn't an official DeepSeek project.
Install
The plugin installs straight from this repository, so the GitHub URL is all you need — no local checkout, and nothing to build by hand.
In the harness. Open Plugins in the sidebar, choose Add plugin, paste this URL, and press Install:
https://github.com/sorsama/deepseek-harness-relay
The first install fetches the plugin's sources and builds them in a temporary copy on your machine, which takes a few seconds. pnpm refuses a git package's build script until you allow it, so the installer asks; choose Allow these scripts and retry. When it finishes, choose Enable now, or switch the bundle on in the list.
From a terminal. The same URL works with the CLI, which forwards to pnpm inside the profile:
dsh plugin --profile web add https://github.com/sorsama/deepseek-harness-relay
For the desktop app, use Plugins inside the app, or target its profile:
dsh plugin --profile desktop add https://github.com/sorsama/deepseek-harness-relay
If the terminal install stops with allowBuilds, copy the block pnpm printed into the profile's pnpm-workspace.yaml and run the same command again. It looks like this:
allowBuilds:
'dsh-relay@https://codeload.github.com/sorsama/deepseek-harness-relay/tar.gz/<commit>': true
The Plugins dialog writes that permission for you.
The URL installs whatever is on main, which is the latest release. To pin a release or a commit, use pnpm's shorthand with a tag or SHA:
dsh plugin --profile web add 'github:sorsama/deepseek-harness-relay#v0.3.5'
Prefer files that are already built? The npm package is the same code with lib/ in it, and installing it runs no build script:
dsh plugin --profile web add dsh-relay
Why this exists
The harness web app only listens on 127.0.0.1, so only the computer running it can open it. That's deliberate. The harness is a coding agent that runs commands on your machine, and its authors refuse dsh web --host 0.0.0.0 because it "would expose remote code execution to the network".
The common workaround is a config patch that binds the harness to 0.0.0.0 with no sign-in at all. After that, anyone on the same Wi-Fi can drive your agent and run commands on your computer.
dsh-relay is the safer way to do it. The harness stays on loopback, and the relay runs as a second listener next to it. Every request gets TLS and a credential check before the relay forwards it.
phone / browser ──TLS──▶ relay :3443 ──plain HTTP──▶ harness 127.0.0.1:3080
├─ /relay/password
├─ /relay/login
├─ /relay/pair
├─ /relay/devices
└─ everything else ─proxy─▶ /api · WebSocket downlinks · web UI
Because the harness never leaves loopback, a relay that crashes or is misconfigured leaves the harness unreachable from the network, never open to it. The relay also refuses to start if it finds the harness already listening on a network address.
Harness 0.1.2 and later have a sign-in of their own (a browser session cookie). They still refuse to bind to the network, still have no TLS, and only hand out that cookie on their own page, so a phone still has no safe way in without something like this relay.
What you get
- Password sign-in from any browser. Too many wrong guesses lock that address out for a while.
- Pairing by QR code or an 8-digit code. Each paired device gets its own token, and you can revoke any device on its own. Codes are single-use, expire after five minutes, and can only be created on the machine running the harness.
- A "sign out everywhere" button that rotates the signing key and logs out every browser and device at once.
- HTTPS, with your own certificate or a self-signed one whose key apps can pin.
- mDNS advertisement on
_dsh._tcp, so apps can find the relay without scanning your subnet. - The full harness web UI, unchanged, with a small Relay link in the corner when the page is served through the relay.
- A Relay action at the sidebar foot, one click from the account menu, that changes the app to the relay's pairing, device, and password pages — in place, in the same window.
- A Computers page that links this relay with another PC in either direction: share this PC, or connect to another one and open its harness in this browser with one click.
- A settings page at Plugins → dsh-relay → Configure on the machine running the harness. Changes apply when you press Save, with no restart.
Supported harness versions
| Harness | dsh-relay |
|---|---|
| 0.1.7-rc.2 through 0.2.x | 0.3 (tested on 0.2.1-rc.3, 0.2.0-rc.2, and 0.1.7-rc.2) |
| 0.1.2 through 0.1.5 | 0.2, installed from its git tag: dsh plugin --profile web add github:sorsama/deepseek-harness-relay#v0.2.1. The 0.2.1 package on npm shipped a stale build that can't authenticate to the harness. |
| 0.1.1 and earlier | 0.1 |
If you install a version that doesn't match your harness, the harness refuses to load it and tells you which range it needs. 0.3 depends on the settings system added in harness 0.1.7, and 0.2 hangs the web app on 0.1.7 and later, so the two can't overlap.
The desktop app
The DeepSeek Harness desktop app runs the same web-app profile, so the relay works there too — it fronts the app's internal loopback server, and you don't need to run dsh web beside it. Install it from inside the app: Plugins → Add plugin, paste the GitHub URL, press Install, then Enable now, and restart the app to load it. https://127.0.0.1:3443/relay/health answers once the relay is up. Do not add a redirect from the harness's own port to the relay's origin: the app's window cannot complete a navigation to the relay's self-signed certificate, and that failure is fatal to the app.
Quick start
New to this? docs/GETTING_STARTED.md walks through every step with npx @deepseek-ai/dsh web, including what you'll see along the way.
Remove the LAN patch if you have one. If
~/.dsh/profiles/web/cordis.patch.ymlbinds the harness to0.0.0.0, delete that row. The relay won't start in front of a harness that's already open to the network.Start the harness. When the plugin is installed and enabled, the harness prints the relay's address as it starts. In the desktop app, quit and reopen it after enabling the plugin.
Set a password. On the machine running the harness, open
https://127.0.0.1:3443/relay/password. Until a password exists, this page only works from that machine, so nobody on your network can claim the relay first.Pair your phone. Still on that machine, open
https://127.0.0.1:3443/relay/pair— or press Relay at the sidebar foot. Scan the QR code with your phone, or open the same path on the phone and type the code. Give the device a name, and it shows up under/relay/devices.The QR names an address your phone can reach, not loopback. A machine with a virtual-machine adapter, a VPN, or two network cards has several addresses, and the page lists them: pick the one your phone is on, then scan. Until you do, the QR uses the best guess. Each choice reads as
<adapter> — <numeric IP>— for exampleWi-Fi — 192.168.1.122orTailscale — 100.121.55.94. Tailscale is shown only when the address is verified to be Tailscale's own (inside100.64.0.0/10orfd7a:115c:a1e0::/48), never just because an adapter is named Tailscale. The list is read when the page loads, so connecting Tailscale or joining a network after the relay started appears on the next reload.
No dsh on your PATH? Every command works as npx @deepseek-ai/dsh ... instead.
You won't be asked for a password on the machine running the harness. Anyone sitting at that keyboard already has a shell, so the relay treats loopback as you. The password is for everything else on the network.
Linking another PC
Both computers run dsh-relay. One of them shows a pairing code; the other enters it once, and from then on either computer can open the other's harness in one click.
- On the computer you want to open, open
https://<its address>:<port>/relay/pair— or press Relay at the sidebar foot, then Pair a device. Note its address, the code, and the certificate pin. - On the computer you are sitting at, press Relay at the sidebar foot, then choose Computers — or open
https://<its address>:<port>/relay/computersin a browser. - Under Connect to another PC, choose the address this computer will offer the other one, then enter the other computer's address, its code, and its pin. Press Connect.
Both Computers pages now list the pair. Open hands this browser a one-time sign-in on the other computer and lands on its harness, with no password to retype. The browser may warn once about that computer's self-signed certificate; accept it for that address.
The other computer records this one at the same moment, so the pair shows on both sides. Unlink on either computer ends it, and Sign out everywhere ends every link along with every session and device. Linking needs TLS on both computers and is refused on plain HTTP; both need Link with other computers on, which is the default.
This works in a browser. The DeepSeek Harness desktop app still cannot load a remote harness, because its window is tied to its own local server.
Using it with DSH Mobile
DSH Mobile 0.8.0 and later support the relay fully. Go to Relay → Pair a relay in the app and scan the QR code or type the code. The app keeps a real token, uses HTTPS, and pins the relay's key, so there's nothing else to set up.
Once every app you use is on 0.8.0 and paired, turn off the compatibility bridge in your config:
compat:
addressGrants: false
Using DSH Mobile 0.5.0 to 0.7.0These older versions came out before the relay existed, and they have two limits.
They can't connect to a self-signed HTTPS server. Up to 0.6.0 the app only spoke http://. 0.7.0 added https://, but only for certificates signed by a trusted authority, which a self-signed relay's isn't. To support them, run a plain HTTP listener next to the HTTPS one:
DSH_RELAY_PLAIN_PORT=3444 dsh web
That listener has no sign-in or pairing pages and can never reach the harness settings or credentials.
They also can't send any credential: no Authorization header, no cookies, no Origin. So instead, you pair from the phone's browser, the relay remembers the phone's network address, and the app is let in when it connects from that same address.
A network address isn't real authentication. It's shared behind NAT, changes with DHCP and IPv6 privacy addresses, and anything on the same Wi-Fi can spoof it. The relay limits the damage (private addresses only, a one-day expiry, removed when you revoke the device, never allowed into settings), but the real fix is updating the app.
If you're writing your own client, docs/CLIENT_INTEGRATION.md is the protocol to follow.
Configuration
There are three places to change settings:
- The settings page at Plugins → dsh-relay → Configure, on the machine running the harness.
- Environment variables for a single run, such as
DSH_RELAY_PORT=8443 dsh web. There are no--relay-*command-line flags, because the harness rejects any flag it doesn't know. - A
relayrow in~/.dsh/profiles/web/cordis.patch.ymlfor permanent changes.
docs/CONFIGURATION.md lists every option, plus how to set up certificates and how to reach the relay from the internet.
Before you expose it to the internet
Read the internet section of the configuration guide first. The short version:
- Forward the relay's port, never the harness's.
- Use a real certificate.
- Set
compat.addressGrants: falseandprivilegedMethods: loopback-only. - Don't point Tailscale Funnel, Tailscale Serve, nginx, or Caddy at
127.0.0.1:3443. Those proxies connect from loopback, and the relay treats loopback as you, so it won't ask anyone for a password.
Security
Signing in to the relay gives you the same power as a shell on the host machine, because the agent runs commands there. Everything in this plugin is designed around that fact. docs/SECURITY.md explains what the relay protects against, what it doesn't, and how to report a vulnerability.
Documentation
| Guide | Read it when |
|---|---|
| Getting started | You're setting up the relay for the first time. |
| Configuration | You want to change ports or certificates, or reach the relay from outside your network. |
| Troubleshooting | Something isn't working. |
| Security | You want to know exactly what the relay protects. |
| Client integration | You're building an app that talks to the relay. |
| Contributing | You want to build, test, or change the plugin. |
Development
pnpm install
pnpm build # tsc -b, then tsdown
pnpm test
pnpm typecheck
A GitHub install runs scripts/prepare.mjs, which does the same tsdown build on its own — no monorepo, no tsc -b, no typecheck — and withdraws the browser half rather than leaving the harness a bundle it refuses to boot with. Keep that script working when you change the build.
CONTRIBUTING.md covers running a source checkout against a real harness and how releases work.
Naming
The harness's brand guidelines ask community projects to use the DSH abbreviation instead of the full trademark, and not to use official brand art. That's why the npm package is dsh-relay and the relay's pages use this project's own logo.
License
MIT
No comments yet. Be the first to write one.