chore(deploy): add optional LiveKit fallback
This commit is contained in:
1 parent
96b2d4f1e6
commit
628ac7c46d
5 files changed
+197
-3
No files matched your search
@@ -19,6 +19,15 @@ MAX_VIEWERS_PER_ROOM=8
|
||||
# Experimental standard-WebRTC relay chains. Keep false outside measured tests.
|
||||
PEER_ASSISTED_MEDIA=false
|
||||
|
||||
# Optional automatic SFU fallback capacity. Set PEER_ASSISTED_MEDIA=true and
|
||||
# supply all three values together; leaving them empty keeps LiveKit completely
|
||||
# dormant. Production requires wss and an independent API secret of 32+ bytes.
|
||||
LIVEKIT_URL=
|
||||
LIVEKIT_API_KEY=
|
||||
LIVEKIT_API_SECRET=
|
||||
# Effective only when the complete LiveKit tuple is configured. Valid range: 1-2.
|
||||
MAX_SFU_ROOTS_PER_ROOM=2
|
||||
|
||||
# ICE servers. Separate multiple URLs with commas.
|
||||
STUN_URLS=
|
||||
TURN_URLS=
|
||||
@@ -31,6 +40,12 @@ TURN_CREDENTIAL_TTL_SECONDS=3600
|
||||
# STUN_URLS=stun:turn.example.com:3478
|
||||
# TURN_URLS=turn:turn.example.com:3478?transport=udp,turn:turn.example.com:3478?transport=tcp
|
||||
# TURN_SHARED_SECRET=replace-with-at-least-32-random-bytes
|
||||
# Optional automatic SFU fallback (requires PEER_ASSISTED_MEDIA=true and does
|
||||
# not replace STUN/TURN above):
|
||||
# LIVEKIT_URL=wss://share.example.com
|
||||
# LIVEKIT_API_KEY=replace-with-a-livekit-api-key
|
||||
# LIVEKIT_API_SECRET=replace-with-at-least-32-independent-random-bytes
|
||||
# MAX_SFU_ROOTS_PER_ROOM=2
|
||||
# Optional TURN/TLS (standard port; append to TURN_URLS when configured):
|
||||
# turns:turn.example.com:5349?transport=tcp
|
||||
# Port 443 is an optional restrictive-network enhancement, not the default.
|
||||
@@ -0,0 +1,27 @@
|
||||
# Minimal single-node LiveKit capacity for Screener's optional automatic SFU
|
||||
# fallback. Copy this file to an untracked service-owned location such as
|
||||
# /etc/livekit/livekit.yaml. Store only the generated key mapping in
|
||||
# /etc/livekit/keys.yaml, owned by the livekit service user with mode 0600.
|
||||
|
||||
port: 7880
|
||||
key_file: /etc/livekit/keys.yaml
|
||||
|
||||
rtc:
|
||||
# These media ports must be reached directly by clients. Port 7880 is only
|
||||
# for the same-host reverse proxy and must be denied by every public firewall.
|
||||
tcp_port: 7881
|
||||
udp_port: 7882
|
||||
use_external_ip: true
|
||||
|
||||
room:
|
||||
auto_create: true
|
||||
# Screener enforces its configured admission limit before issuing a token.
|
||||
# This server-side ceiling covers the repository's maximum 16 viewers + host.
|
||||
max_participants: 17
|
||||
|
||||
logging:
|
||||
level: info
|
||||
pion_level: error
|
||||
|
||||
# Redis, embedded TURN, recording, ingress, egress, and webhooks are omitted on
|
||||
# purpose. This first fallback deployment is one process on one node.
|
||||
@@ -37,6 +37,47 @@ server {
|
||||
add_header X-Frame-Options "DENY" always;
|
||||
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
|
||||
|
||||
# Optional LiveKit signaling for automatic SFU fallback. Set LIVEKIT_URL to
|
||||
# wss://share.bonfire.icu. Legacy clients use the exact /rtc endpoint.
|
||||
location = /rtc {
|
||||
# The WebSocket query contains a short-lived LiveKit join token. Do not
|
||||
# persist the request target in either access or error logs.
|
||||
access_log off;
|
||||
error_log /dev/null crit;
|
||||
proxy_pass http://127.0.0.1:7880;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
proxy_set_header X-Forwarded-Proto https;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $screener_connection_upgrade;
|
||||
proxy_read_timeout 5h;
|
||||
proxy_send_timeout 5h;
|
||||
proxy_buffering off;
|
||||
}
|
||||
|
||||
# Current clients use versioned paths below /rtc/.
|
||||
location ^~ /rtc/ {
|
||||
# The WebSocket query contains a short-lived LiveKit join token. Do not
|
||||
# persist the request target in either access or error logs.
|
||||
access_log off;
|
||||
error_log /dev/null crit;
|
||||
proxy_pass http://127.0.0.1:7880;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
proxy_set_header X-Forwarded-Proto https;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $screener_connection_upgrade;
|
||||
proxy_read_timeout 5h;
|
||||
proxy_send_timeout 5h;
|
||||
proxy_buffering off;
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:8787;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
[Unit]
|
||||
Description=LiveKit single-node SFU fallback for Screener
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=livekit
|
||||
Group=livekit
|
||||
ExecStartPre=/usr/bin/test -r /etc/livekit/livekit.yaml
|
||||
ExecStartPre=/usr/bin/test -r /etc/livekit/keys.yaml
|
||||
ExecStart=/usr/local/bin/livekit-server --config /etc/livekit/livekit.yaml
|
||||
Restart=on-failure
|
||||
RestartSec=3s
|
||||
TimeoutStopSec=20s
|
||||
UMask=0077
|
||||
LimitNOFILE=65535
|
||||
|
||||
NoNewPrivileges=true
|
||||
PrivateDevices=true
|
||||
PrivateTmp=true
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
ProtectKernelTunables=true
|
||||
ProtectKernelModules=true
|
||||
ProtectKernelLogs=true
|
||||
ProtectControlGroups=true
|
||||
ProtectClock=true
|
||||
ProtectHostname=true
|
||||
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX AF_NETLINK
|
||||
RestrictNamespaces=true
|
||||
RestrictRealtime=true
|
||||
RestrictSUIDSGID=true
|
||||
LockPersonality=true
|
||||
CapabilityBoundingSet=
|
||||
SystemCallArchitectures=native
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
+75
-3
@@ -8,6 +8,11 @@ Caddy or nginx; coturn is the separate STUN/TURN service. Normal media remains
|
||||
browser-to-browser. Only an ICE pair that cannot connect directly consumes TURN
|
||||
bandwidth.
|
||||
|
||||
A deployment may additionally provide one single-node LiveKit process as the
|
||||
automatic final media fallback. This capacity is dormant unless the complete
|
||||
`LIVEKIT_URL`/key/secret tuple is configured. It does not replace the P2P path,
|
||||
the peer-assisted experiment, or the required application STUN/TURN settings.
|
||||
|
||||
The public staging infrastructure has already passed the relay checks recorded
|
||||
in `docs/status.md`, but every new deployment must run the direct, relay, and
|
||||
mixed-network procedures below. Configuration validation alone is not evidence
|
||||
@@ -52,6 +57,12 @@ explicitly sets `LISTEN_HOST=127.0.0.1` because only the same-host reverse proxy
|
||||
should connect. A container can instead use `0.0.0.0` and enforce the intended
|
||||
boundary with port publishing rules or a host firewall.
|
||||
|
||||
The optional same-host LiveKit layout needs no additional public hostname:
|
||||
`LIVEKIT_URL=wss://share.example.com` and nginx forwards only the exact `/rtc`
|
||||
endpoint and paths below `/rtc/` to LiveKit. Its HTTP/WebSocket listener on TCP
|
||||
7880 is private to nginx, while WebRTC media reaches LiveKit directly on TCP
|
||||
7881 or UDP 7882.
|
||||
|
||||
## Production application environment
|
||||
|
||||
Keep the real values in the process secret store or an untracked, access-restricted
|
||||
@@ -83,6 +94,16 @@ TURN_SHARED_SECRET=<SAME_VALUE_AS_COTURN_STATIC_AUTH_SECRET>
|
||||
TURN_CREDENTIAL_TTL_SECONDS=3600
|
||||
```
|
||||
|
||||
To make automatic SFU fallback capacity available, add the complete tuple:
|
||||
|
||||
```dotenv
|
||||
PEER_ASSISTED_MEDIA=true
|
||||
LIVEKIT_URL=wss://share.example.com
|
||||
LIVEKIT_API_KEY=<GENERATED_LIVEKIT_API_KEY>
|
||||
LIVEKIT_API_SECRET=<INDEPENDENT_SECRET_OF_AT_LEAST_32_BYTES>
|
||||
MAX_SFU_ROOTS_PER_ROOM=2
|
||||
```
|
||||
|
||||
`ALLOWED_ORIGINS` must list exact `http` or `https` origins, never `*`.
|
||||
`ACCESS_PASSWORD` is optional: omit it or leave it empty for a public site. A
|
||||
non-empty value must contain 1 through 128 visible ASCII characters (`0x21`
|
||||
@@ -101,6 +122,16 @@ browsers receive HMAC-SHA1-derived, time-limited credentials after room
|
||||
authentication. Keep host clocks synchronized because the credential username
|
||||
contains its Unix expiry time.
|
||||
|
||||
The three `LIVEKIT_*` values must either all be absent or all be present, and a
|
||||
complete tuple requires `PEER_ASSISTED_MEDIA=true`. An empty tuple keeps the
|
||||
optional SDK and server path dormant. `LIVEKIT_URL` must be a plain `ws:` or
|
||||
`wss:` origin with no `/rtc` suffix; production requires `wss:`.
|
||||
`LIVEKIT_API_SECRET` must contain at least 32 bytes and must not reuse
|
||||
`ACCESS_PASSWORD` or `TURN_SHARED_SECRET`. `MAX_SFU_ROOTS_PER_ROOM` defaults to
|
||||
2 and accepts only 1 or 2; it is ignored when LiveKit is not configured. These
|
||||
credentials authorize short-lived LiveKit room tokens and do not provide E2EE:
|
||||
the LiveKit operator can access ordinary SFU media.
|
||||
|
||||
When `ACCESS_PASSWORD` is configured, both host and viewer routes first show the
|
||||
same login gate. Only `POST /api/session` accepts the password in an
|
||||
`Authorization: Bearer` header, then returns a 12-hour stateless HMAC-SHA256
|
||||
@@ -192,7 +223,11 @@ location / {
|
||||
The tracked
|
||||
[`share.bonfire.icu.conf.example`](../deploy/nginx/share.bonfire.icu.conf.example)
|
||||
follows this simple model and listens directly on public TCP 443. It does not
|
||||
depend on the optional SNI router.
|
||||
depend on the optional SNI router. Its optional exact `/rtc` and `/rtc/` prefix
|
||||
locations preserve the LiveKit request URI and disable both access logging and
|
||||
request-line error logging. Legacy `/rtc?token=...` and current versioned
|
||||
requests carry a short-lived LiveKit JWT in the query string, so neither request
|
||||
target may fall through to the site's ordinary logs.
|
||||
|
||||
When Certbot manages the Web certificate, install the tracked
|
||||
[`reload-nginx.sh`](../deploy/certbot/reload-nginx.sh) as an executable under
|
||||
@@ -213,6 +248,39 @@ TURN reachability, or any external dependency, so use it only to decide whether
|
||||
the Node process can accept HTTP requests. It is not a deployment-readiness or
|
||||
end-to-end media check.
|
||||
|
||||
## Optional single-node LiveKit fallback
|
||||
|
||||
Use the tracked
|
||||
[`livekit.yaml.example`](../deploy/livekit/livekit.yaml.example) and
|
||||
[`livekit.service.example`](../deploy/systemd/livekit.service.example) as the
|
||||
minimal single-node baseline. Install a reviewed, pinned LiveKit Server release
|
||||
from its official release assets, generate an independent key pair with
|
||||
`livekit-server generate-keys`, and place only the YAML key mapping in
|
||||
`/etc/livekit/keys.yaml`. Keep that file owned by the `livekit` service account
|
||||
with mode `0600`; put the same values in Screener's untracked process secrets.
|
||||
|
||||
The example deliberately omits Redis and every recording, ingress, egress,
|
||||
webhook, and embedded-TURN service. Do not add Redis for this one-node workload.
|
||||
The service journal is the diagnostic log; keep its retention finite and access
|
||||
restricted. Never enable debug/Pion packet logging continuously or persist JWTs,
|
||||
SDP, ICE candidates, API secrets, or full `/rtc` and `/rtc/*` request targets.
|
||||
|
||||
Configure both the host firewall and the provider firewall independently:
|
||||
|
||||
| Destination | Protocol | Exposure | Purpose |
|
||||
| --- | --- | --- | --- |
|
||||
| `127.0.0.1:7880` | TCP | Private | nginx to LiveKit signaling/API |
|
||||
| public host `:7881` | TCP | Public | WebRTC ICE/TCP fallback |
|
||||
| public host `:7882` | UDP | Public | WebRTC ICE/UDP mux |
|
||||
|
||||
LiveKit may listen beyond loopback while it discovers and advertises public
|
||||
media addresses, so the public-firewall denial of TCP 7880 is mandatory; nginx
|
||||
must be its only ingress. TCP 7881 and UDP 7882 are direct media listeners and
|
||||
must not be placed behind the HTTP reverse proxy. If the host is behind NAT,
|
||||
forward them without port translation and verify the advertised candidate from
|
||||
an external network. LiveKit ICE/TCP is not equivalent to authenticated TURN;
|
||||
strict-network SFU reachability remains unproven until separately tested.
|
||||
|
||||
## coturn
|
||||
|
||||
Copy [`deploy/coturn/turnserver.conf.example`](../deploy/coturn/turnserver.conf.example)
|
||||
@@ -262,6 +330,8 @@ Open only these public listeners:
|
||||
| `turn.example.com:49152-49251` | UDP, bidirectional | Relayed media endpoints |
|
||||
| `turn.example.com:5349` | TCP, optional | Standard TURN/TLS |
|
||||
| `turn.example.com:443` | TCP, optional | TURN/TLS on a dedicated IP or validated L4/SNI route |
|
||||
| host public address `:7881` | TCP, optional SFU | LiveKit WebRTC ICE/TCP |
|
||||
| host public address `:7882` | UDP, optional SFU | LiveKit WebRTC ICE/UDP mux |
|
||||
|
||||
The 100-port relay range is an initial small-room limit, not a universal sizing
|
||||
rule. Monitor 508/allocation failures and concurrent allocations before widening
|
||||
@@ -318,5 +388,7 @@ References: [coturn 4.17.2 release](https://github.com/coturn/coturn/releases/ta
|
||||
the [official example configuration](https://github.com/coturn/coturn/blob/master/examples/etc/turnserver.conf),
|
||||
[TURN URI scheme RFC 7065](https://www.rfc-editor.org/rfc/rfc7065.html),
|
||||
[Cloudflare network-port guidance](https://developers.cloudflare.com/fundamentals/reference/network-ports/),
|
||||
[RFC6265bis](https://datatracker.ietf.org/doc/draft-ietf-httpbis-rfc6265bis/), and
|
||||
[Node.js Crypto](https://nodejs.org/api/crypto.html#cryptocreatehmacalgorithm-key-options).
|
||||
[RFC6265bis](https://datatracker.ietf.org/doc/draft-ietf-httpbis-rfc6265bis/),
|
||||
[Node.js Crypto](https://nodejs.org/api/crypto.html#cryptocreatehmacalgorithm-key-options),
|
||||
[LiveKit firewall guidance](https://docs.livekit.io/deploy/admin/firewall/), and
|
||||
the [official LiveKit configuration sample](https://github.com/livekit/livekit/blob/master/config-sample.yaml).
|
||||
Reference in new issue
Block a user