Files
Piik/docs/operations/self-hosting.md
T
AAA 3d960dc5bd docs: simplify repository truth architecture (#295)
Modularize durable truth, bound always-loaded instructions, and keep domain-document size checks advisory. Local cross-platform repository hygiene checks pass; GitHub-hosted steps were not started because of the account billing state.
2026-08-27 11:45:24 +08:00

90 lines
4.5 KiB
Markdown

# Self-Hosting Operations
This runbook owns initial single-host service setup. Application releases use
[deployment](../deployment.md); accepted environment values and ports are in
[configuration reference](../reference/configuration.md).
## Topology
```text
Browser -- HTTPS/WSS --> nginx :443 --> Screener :8787
Browser -- /rtc/v1 WSS --> nginx :443 --> LiveKit :7880
Browser <---------- DTLS-SRTP P2P ----------> Browser
Browser -------- ordinary STUN/UDP --------> coturn :3478
Browser <--------- DTLS-SRTP/UDP ----------> LiveKit :7882
Screener -------- private RoomService -----> LiveKit :7880
```
The tracked public baseline uses Node.js 24, nginx, a valid Web TLS
certificate, time synchronization, and coturn 4.17.2 or a newer patched release.
LiveKit is required for the accepted SFU fallback and tracked release wrapper.
Web and STUN may use different DNS names on the same public IP. Another proxy or
P2P-only service shape needs its own matching updater and recovery checks.
Expose only the public listeners in
[configuration reference](../reference/configuration.md). Screener 8787 and
LiveKit 7880 stay private.
## Tracked Templates
- [Screener systemd unit](../../deploy/systemd/screener.service.example)
- [LiveKit systemd unit](../../deploy/systemd/livekit.service.example)
- [LiveKit readiness drop-in](../../deploy/systemd/screener-livekit-readiness.conf.example)
- [coturn systemd unit](../../deploy/systemd/coturn.service.example)
- [STUN-only coturn config](../../deploy/coturn/turnserver.conf.example)
- [LiveKit config](../../deploy/livekit/livekit.yaml.example)
- [nginx site](../../deploy/nginx/share.bonfire.icu.conf.example)
Copy templates outside the repository, inject independent secrets through an
access-restricted environment file or service manager, and adapt only addresses,
domains, certificates, users, and resource limits required by the host.
## Initial Setup
1. Configure DNS and TLS for the Web origin and STUN name.
2. Install Node.js, nginx, coturn, and pinned-compatible LiveKit.
3. Create an unprivileged `screener` service account, `/opt/screener/releases`,
`/opt/screener/uploads`, and an access-restricted environment file.
4. Provision one verified initial immutable release and atomically point
`/opt/screener/current` to it before enabling the unit. The tracked release
wrapper is upgrade-only and deliberately refuses a missing prior release;
this repository does not provide a generic first-install transaction.
5. When stable room authority is enabled, use the service-owned
`/var/lib/screener` StateDirectory and include the SQLite file in the host's
state backup/recovery policy.
6. Install the tracked service and proxy templates. Bind Screener to loopback on
bare metal; containers may bind `0.0.0.0` only when publishing/firewall rules
preserve the same boundary.
7. Apply the public-port allowlist and confirm every retired TURN/TCP port
is closed.
8. Start coturn and LiveKit before Screener, then nginx. The LiveKit
readiness drop-in waits for its private control listener before Screener.
LiveKit must be dedicated to this Screener application, set
`room.auto_create: false`, and expose its control listener only to the proxy and
application host. Screener binds its own listener before touching LiveKit,
rejects foreign room names, removes stale managed rooms, confirms the namespace
empty, and only then installs signaling. A competing application process must
make no LiveKit mutation.
Coturn runs `stun-only`, `no-tcp`, and `no-tls`. It must answer STUN binding and
reject TURN allocation. Avoid verbose STUN/ICE logging because infrastructure
necessarily observes client IP addresses.
## Operational Verification
- `/healthz` returns `{"status":"ok"}` locally and through the public origin.
- Screener, nginx, coturn, and LiveKit are active with expected restart
counts and bounded logs/resources.
- The official Trickle ICE sample obtains an ordinary UDP `srflx` candidate from
the configured STUN service and no relay candidate.
- A direct room presents media on two networks when Peer ICE succeeds.
- A constrained route creates one managed Host publication and only admitted
subscriptions over LiveKit UDP; Peer descendants remain ordinary P2P.
- Blocking all UDP reaches a clear bounded failure.
- Restarting Screener in stable mode retains room authority while Browser
sessions and media reconnect from fresh process state.
Representative network, mobile, audio, 20-Viewer, and long-running evidence is
tracked in [verification status](../verification-status.md), not in this runbook.