Skip to main content
By the end of this page you have made the one decision every deployment makes — how the connection is protected — and applied it. The daemon binds 127.0.0.1:8137 by default: loopback only, nothing to decide. The moment you want other machines to reach it, you must also say how the traffic is protected. A 0.0.0.0 bind without an answer refuses to boot rather than serve auth tokens and pairing secrets unencrypted by accident:

Which one?

Tokens are required on every non-loopback connection in both postures — the decision is about encryption on the wire, not about whether auth exists. The web-app row is the browser’s rule, not the daemon’s: the Workbench needs crypto.subtle to mint its identity, and browsers withhold it on plain-HTTP origins that are not loopback, so a LAN URL like http://<server>:8137/ loads and then refuses to start. It binds the served web app alone — the extension and desktop app speak ws://<server>:8137 in either posture, which is why a headless server with no browser on it is a perfectly ordinary deployment.

Option A — cleartext on a trusted LAN

An explicit acknowledgment that cleartext on a trusted network is acceptable:
ohd status lists the LAN join URLs the running daemon actually answers at. If clients still cannot connect, check that the host firewall (ufw/firewalld) admits port 8137 — the daemon logs every connection it refuses, so a client that fails while the log stays silent never reached the process at all. The daemon warns at boot as a standing reminder of the posture:
Undo it any time with ohd install --no-allow-insecure-lan and a restart.

Option B — TLS terminated at a reverse proxy

TLS is reverse-proxy-first: terminate wss:// at Caddy or nginx and forward plain ws:// to the daemon on loopback. The daemon stays bound to 127.0.0.1 when the proxy runs on the same machine — only the proxy is reachable from outside.
Two flags, two jobs:
  • --trusted-proxy makes auth logs, rate limits, and the claim’s loopback test use the client address the proxy appends to X-Forwarded-For instead of the proxy’s own — without it a proxy on the same machine would make every remote browser look local and the setup code would gate nothing. Never set it without a proxy in front — clients could then spoof the header.
  • --allowed-host admits the proxy’s domain on the browser-facing routes. IP addresses, localhost, and mDNS *.local names always work; any other hostname — a reverse-proxy domain, an intranet name — must be declared, or its requests are refused.
Caddy (automatic certificates; WebSocket upgrades and X-Forwarded-For are handled by default):
nginx:
Clients then dial wss://oh.example.com with a paired token, exactly like a LAN join.

Switching later

Both postures persist through daemon.json, so switching is a re-install plus restart — for example, from cleartext LAN to a proxy:
Existing tokens keep working; clients just dial the new URL.