Skip to content
dsh.fish
Bundle

@sysit/dsh-remote-access

Out-of-tree dsh web-profile bundle: serve the Web UI on all interfaces (env DSH_WEB_HOST) behind the built-in ?token= BrowserAuth and auto-print the LAN URL. Single webserver row — no auth fork, stays composable with built-in BrowserAuth.

Source
sysit
License
MIT
Updated
Updated 6 days ago

Readme

# dsh-remote-access

Out-of-tree [deepseek-harness](https://github.com/deepseek-harness) web-profile **bundle** that lets the `dsh --profile web` GUI listen on **all interfaces** (`0.0.0.0`) so you can open it from another device — while keeping the **built-in `?token=` BrowserAuth and never touching authentication**.

It is intentionally tiny: **one `webserver` row**. Unlike earlier plugins, it does **not** fork `web-startup` / `webserver` / `connection` and does **not** invent its own token gate. That is precisely why it survives dsh upgrades: the auth and the LAN `?token=` URL printing already come from dsh itself; this bundle only lets `host` be non-loopback.

## How it works

- dsh's `BrowserAuth` (`client/connection`) issues a **host-bound** cookie (`dsh-auth-<sha256(authority)>`) when you open the printed `?token=` URL. It already works for a LAN bind.
- `web-app` prints the LAN URL `(LAN: http://<ip>:<port>/?token=...)` whenever the server binds `0.0.0.0`.
- The only blocker in stock dsh is `web-startup` refusing `--host 0.0.0.0`. This bundle **does not unblock that flag**; instead it overrides the `webserver` row's `host` from an env var, so you never pass `--host`.
- Result: zero third-party, zero plugins that own the auth, and a **profile-level patch** the loader re-reads on every boot — so it needs no re-apply after a dsh upgrade.

## Install

```sh
# from a git checkout
dsh plugin --profile web install github:sysit/dsh-remote-access

# or from a local path (e.g. while developing)
dsh plugin --profile web install file:/Path/dsh-remote-access
```

That adds `@sysit/dsh-remote-access` to the profile's `dsh.profile.bundles` (after `dsh-web-app`, so its `webserver` override wins).

## Use

| Want | Command |
|---|---|
| **Remote** (default when set) | `export DSH_WEB_HOST=0.0.0.0 && dsh --profile web --no-open` |
| **Loopback only** | unset `DSH_WEB_HOST`, or `DSH_WEB_HOST=127.0.0.1 dsh --profile web` |
| launchd/KeepAlive | add `export DSH_WEB_HOST="\${DSH_WEB_HOST:-0.0.0.0}"` to the launch script |

On a remote bind the startup log prints both:

```
dsh web: http://127.0.0.1:3080/?token=eqeU… (LAN: http://192.168.1.5:3080/?token=eqeU…)
```

Open the `LAN:` URL on another device — no 401, no plugin auth, no relay. The token is **per-process** (changes each restart); the browser cookie is valid up to `cookieMaxAgeDays` (default 30 days), so an already-open tab keeps working across restarts.

## Upgrade handling

Nothing to re-apply. The patch is a declarative layer in `~/.dsh/profiles/<profile>/` (outside the dsh repo), re-read on every boot. After a dsh upgrade, smoke-check:

```sh
launchctl kickstart -k gui/$(id -u)/com.deepseek-ai.dsh-web   # restart your web service
tail -5 ~/Library/Logs/dsh/web.out.log                        # expect `?token=` + `(LAN: ...)`
```

If dsh ever renames the `webserver` row id or its config keys, regenerate the row from the current official patch:

```sh
dsh --profile web --dump-config                              # current webserver keys
cat packages/bundle/web-app/cordis.patch.yml                  # official webserver row
```

## Security notes

- `0.0.0.0` exposes the harness to your network. The `?token=` gate + host-bound cookie are the auth; treat the printed token as a secret and use `--no-open` when remote.
- Cross-site/DNS-rebinding defense stays on (dsh `api-request-trust`); `trustedHosts` still pick up LAN literals automatically.
- The `/api` RPC surface is only as exposed as you make it — prefer SSH forwarding or a VPN if the network is not trusted.

## License

MIT

Install

dsh plugin --profile web add github:sysit/dsh-remote-access

Profile: web

  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source