3.3 KiB
Multi-node deployment
Background
This recipe publishes WebRTC media ports (TCP 7881, UDP 7882) directly on the host using mode: host in Docker Swarm. This is necessary because these ports carry raw RTP media packets — they are not HTTP traffic and cannot be proxied through Traefik.
The WebRTC protocol requires these specific port numbers. LiveKit advertises them as ICE candidates to clients, so they cannot be remapped to different host ports. This means only one LiveKit instance can run per host, regardless of how the ports are exposed (the same constraint applies to email servers on port 25, for example).
Single-node deployments
On a single-node swarm (the typical Co-op Cloud setup), this works without any additional configuration. The ports are published on the only available node, and DNS for LIVEKIT_DOMAIN points to that same node.
Multi-node deployments
On a multi-node swarm, mode: host binds the port on whichever node the container is scheduled to. This creates two considerations:
-
DNS must point to the correct node. The
LIVEKIT_DOMAINDNS record must resolve to the IP of the node actually running the LiveKit container, not just any swarm node. -
Firewall rules must target the correct node. Ports 7881/tcp and 7882/udp must be open on the node running LiveKit.
Option A: Placement constraints (simplest)
Pin the LiveKit service to a specific node using a compose override:
# compose.override.yml
services:
livekit:
deploy:
placement:
constraints:
- node.hostname == your-livekit-node
Then point LIVEKIT_DOMAIN DNS to that node's IP and open the firewall ports there.
Option B: Traefik entrypoints (centralized port management)
Instead of publishing ports directly on the LiveKit service, route them through Traefik as entrypoints. This way all exposed ports are on the Traefik node(s).
- Add a Traefik compose override (e.g.
compose.lasuite-meet.yml) that publishes the ports on the Traefik service:
services:
app:
ports:
- target: 7881
published: 7881
protocol: tcp
mode: host
- target: 7882
published: 7882
protocol: udp
mode: host
- Add Traefik entrypoints in
traefik.yml.tmpl:
entryPoints:
livekit-tcp:
address: ":7881"
livekit-udp:
address: ":7882/udp"
- In the lasuite-meet compose.yml, remove the
ports:from the livekit service and add Traefik TCP/UDP router labels instead:
services:
livekit:
# Remove ports: section
deploy:
labels:
# Keep existing HTTP labels for signaling...
# Add TCP router for ICE/TCP
- "traefik.tcp.routers.${STACK_NAME}_livekit_ice.rule=HostSNI(`*`)"
- "traefik.tcp.routers.${STACK_NAME}_livekit_ice.entrypoints=livekit-tcp"
- "traefik.tcp.services.${STACK_NAME}_livekit_ice.loadbalancer.server.port=7881"
# Add UDP router for ICE/UDP
- "traefik.udp.routers.${STACK_NAME}_livekit_media.entrypoints=livekit-udp"
- "traefik.udp.services.${STACK_NAME}_livekit_media.loadbalancer.server.port=7882"
This centralizes port management on Traefik but requires modifying the Traefik recipe configuration. The Nextcloud Talk HPB recipe uses this same pattern for TURN/STUN on port 3478.