# dsh-loopback-bridge
Use DSH settings over a LAN IP or public hostname, not just localhost
Install and restart · No official source edits · Put auth in front of the entry
**[中文](README.md)** · English
---
> [!WARNING]
> This plugin opens the “localhost-only” settings and credential-write surface to anyone who can load the DSH page. Fine on a home LAN you already trust; on the public internet, put authentik / oauth2-proxy (or equivalent) in front. Back up first. Data loss is on you.
## What is this
The DSH settings page only treats the UI as writable when the address bar looks local (`127.0.0.1` / `localhost`). Open it via `192.168.x.x` or your own domain and you get *"settings are unavailable in this browser"* — the Models tab will not save.
From 0.1.2 the server already honors `--trusted-host`, so the RPCs themselves can succeed. The blocker is the browser: the settings UI sees a non-loopback hostname, drops into read-only, and never sends the request. This plugin marks the connection as loopback at page load so settings work again.
## ✨ Features
- **Remote settings actually write** — LAN IP, NAS name, or public domain: models and API keys save
- **No official package edits** — upgrade DSH as you like; remove this plugin if upstream ever trusts the hostname
- **Works after install** — `dsh plugin add`, restart web, no nginx Host hacks
- **0.1.2-safe** — do **not** rewrite Host to `127.0.0.1`; the auth cookie is bound to the real Host and will 401
## 🚀 Quick start
### 1. Trust the Host you actually open
`dsh web` must list every hostname / IP you use in the address bar:
```bash
dsh web --host 127.0.0.1 --port 3080 \
--trusted-host 192.168.31.229 \
--trusted-host dsh.example.com
```
### 2. Install the plugin
```bash
dsh plugin --profile web add github:johnhom1024/dsh-loopback-bridge
```
Local development:
```bash
dsh plugin --profile web add link:/path/to/dsh-loopback-bridge
```
### 3. Restart `dsh web`
On Docker stacks that share a netns, recreate the whole stack — do not `restart` a single container. Refresh the page and open Settings → Models from the remote URL.
## ⚙️ Requirements
| Item | Notes |
| --- | --- |
| DSH | Verified on `0.1.2-rc.1`. `0.1.5+` needs 1.0.1 (older builds wipe the official `__ModuleLoader__` and the page dies with bootstrap facade is missing). Pre-0.1.2 still needed Host rewrites; skip them |
| `--trusted-host` | Must cover the hostname / IP in the address bar |
| Reverse proxy | **Do not** rewrite privileged API Host to `127.0.0.1` (0.1.2 cookies bind to Host) |
| Auth | LAN trust is fine; public entry needs a reverse-proxy login |
## Verify
Open settings on the remote URL. If the Models tab is no longer *unavailable* and an API key saves, you are done.
Optional curl checks
```bash
# Script is reachable
curl -s -o /dev/null -w "%{http_code} %{size_download}B\n" http:///loopback-bridge.js
# First-byte HTML inject
curl -s http:/// | grep loopback-bridge
# Settings RPC (0.1.2 uses slash paths; send your session cookie)
curl -s -o /dev/null -w "%{http_code}\n" -X POST \
-H "Content-Type: application/json" \
-d '{"type":"client-request","rpcId":"t","method":"settings/describe","payload":{"args":{}}}' \
http:///api/settings/describe
```
## 🔒 Security
The plugin only touches the client. Anyone who can open the DSH page can change settings and call `credentials.set`. That is the right model behind your own reverse proxy, and the wrong one on a naked public port.
If upstream later issues `isLoopback` from the server, this plugin will stop working — just uninstall it.
## 📄 License
[MIT](LICENSE)