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:
ohd install --no-allow-insecure-lan and a
restart.
Option B — TLS terminated at a reverse proxy
TLS is reverse-proxy-first: terminatewss:// 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.
--trusted-proxymakes auth logs, rate limits, and the claim’s loopback test use the client address the proxy appends toX-Forwarded-Forinstead 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-hostadmits the proxy’s domain on the browser-facing routes. IP addresses,localhost, and mDNS*.localnames always work; any other hostname — a reverse-proxy domain, an intranet name — must be declared, or its requests are refused.
X-Forwarded-For are handled by default):
wss://oh.example.com with a paired token, exactly
like a LAN join.
Switching later
Both postures persist throughdaemon.json, so switching is a
re-install plus restart — for example, from cleartext LAN to a proxy: