Access Levels
The host listens on a fixed port (8787) so SSH tunnels have a stable target. Three independent toggles control who can reach it:
Network access requires Allow remote access to be on first — it widens the same host from loopback to every interface. Turning remote access off also disables LAN access.
Allow remote access (loopback)
The safest level. The backend binds127.0.0.1 only, so nothing is reachable over the network — but an SSH tunnel can forward into it. This is the right setting when you’ll connect from another machine over SSH.
When it’s on, the panel lists copyable addresses and the pairing token:
Network access (LAN)
Also binds0.0.0.0, so your LAN IP and Tailscale IP accept connections directly — no SSH needed. It’s less private (the port is visible on the network), so every connection is gated by the pairing token.
Tailscale HTTPS
Exposes the loopback backend over your tailnet’s HTTPS endpoint usingtailscale serve. Tailscale provisions a TLS certificate for the MagicDNS name automatically, so peers reach a clean https://<machine>.<tailnet>.ts.net URL over wss:// — with no port-forwarding and no manual certificates. The backend itself keeps listening only on 127.0.0.1.
Pairing Token
A token is generated automatically the first time you expose the machine. It’s appended to web URLs as?token=… and required on every WebSocket connection. Copy it into the connecting client’s Pairing token field, or hand out the web URL that already embeds it.
Opening In A Browser
Each address has a Copy browser link button (http://<host>:8787/?token=…) that loads the full Mains UI in a web browser — ideal for a phone or tablet.
The installed Mains app bundles the web interface, so this works out of the box: the same renderer the desktop window uses is served over HTTP on the exposure port.
Running Mains from source? In development the interface comes from the Vite dev server, so there’s no build on disk to serve. Build it once in the repo:Until you do, the panel shows a “Web UI not built” notice and only the WebSocket endpoint (for another Mains desktop client) works.
Persistence & Teardown
- Exposure toggles are remembered across launches — Tailscale Serve is re-applied off the startup critical path so cert provisioning never delays launch.
- On quit, the host is torn down and
tailscale serveis stopped, so nothing keeps proxying to a closed app. - The exposure controls run on local IPC only — a connected remote client can never toggle the access it’s connected through.
Next Steps
1
From another Mains desktop app
Take the address shown here, swap
http/https for ws/wss, and paste it into a Direct connection.2
From a phone or browser
Copy the browser link and open it — the token is already embedded.
3
Over SSH instead
Leave only Allow remote access on and connect with an SSH tunnel.
