Self-host
Secrets, listeners, and what to expose.
Expose the Harmony Chat server and nothing else. Workers make outbound connections, so they need no inbound ports.
Listeners
harmony server start --listen loopback # default
harmony server start --listen lan --port 8080 # LAN
harmony server start --listen tailnet # Tailnet only
harmony server start --listen custom # explicit bindLoopback uses local_trusted: a request from 127.0.0.1 is trusted, so no login screen appears. Any
other listener requires a claim step, and people join by invite.
Secrets
Set these before you move off loopback.
| Variable | Guards |
|---|---|
JWT_SECRET | Session tokens |
INTERNAL_SECRET | Internal API surfaces |
ADMIN_SECRET | Admin operations |
HARMONY_WORKER_TOKEN | Which workers may dial this main server |
Rotate before you expose
The development defaults in this repo are not secrets. Generate real values before a listener is reachable by anyone you did not invite.
Data
PGlite under $HARMONY_HOME/data/ is the product source of truth: messages, groups, files metadata,
agent state. Back it up by stopping the server and copying that directory — one embedded database,
one writer.
Workers
# on the extra machine
harmony server start --workerA worker dials HARMONY_SERVER_URL over outbound WSS with a matching HARMONY_WORKER_TOKEN. It opens
no inbound port and holds no copy of chat data.
Check what dialled in:
curl -sf -H "x-internal-secret: $INTERNAL_SECRET" \
http://127.0.0.1:8080/api/v1/workers/statusChecklist before you expose
- Real values for all four secrets above.
- Narrowest listener that works —
tailnetbeforelan,lanbefore a public bind. - TLS terminator or reverse proxy in front of :8080 if clients are off-network.
- Clients pointed at the server URL — see Clients.
- Worker capacity visible in Settings → Capacity.