Skip to content

LiveKit Configuration

LiveKit is the WebRTC media server at the heart of La Suite Meet. Every deployment needs a properly configured LiveKit instance.

TLS requirement — important

Browsers running on HTTPS pages cannot connect to unencrypted WebSocket endpoints (ws://). They require wss:// (WebSocket over TLS). LiveKit on port 7880 serves plain WebSocket with no TLS.

You must put TLS in front of LiveKit. The recommended way in a Docker Compose deployment is to proxy LiveKit through nginx-proxy on a dedicated subdomain (e.g., livekit.example.com). nginx-proxy terminates TLS and forwards traffic to LiveKit's port 7880 inside Docker.

This means you need three DNS records pointing to your server:

visio.example.com    →  <server-IP>   (Meet frontend + API)
auth.example.com     →  <server-IP>   (Keycloak)
livekit.example.com  →  <server-IP>   (LiveKit WebSocket, TLS-terminated by nginx-proxy)

LiveKit configuration file

Create livekit-server.yaml:

port: 7880
rtc:
  tcp_port: 7881
  udp_port: 7882
  use_external_ip: true  # required on cloud VMs behind NAT

keys:
  meetapikey: your-livekit-api-secret-here  # must match LIVEKIT_API_KEY / LIVEKIT_API_SECRET

redis:
  address: redis:6379

logging:
  level: info

Key settings

rtc.use_external_ip: Set to true on any cloud server behind NAT. LiveKit auto-detects and announces its public IP via STUN.

keys: API key → API secret map. Must match LIVEKIT_API_KEY and LIVEKIT_API_SECRET in your .env.

redis: LiveKit uses Redis for distributed room state. Point this to the same Redis instance as Meet.

For participants on restrictive corporate networks where UDP is blocked:

rtc:
  turn_servers:
    - host: turn.example.com
      port: 443
      protocol: tls
      username: turnuser
      credential: turnpassword

Docker Compose service

LiveKit is added to both the proxy network (for nginx-proxy TLS termination) and the internal network (for Redis access). Port 7880 is not exposed on the host — it is proxied by nginx-proxy. Ports 7881 and 7882 are still exposed directly for media transport.

livekit:
  image: livekit/livekit-server:latest
  restart: unless-stopped
  command: --config /config.yaml
  environment:
    - VIRTUAL_HOST=livekit.example.com
    - VIRTUAL_PORT=7880
    - LETSENCRYPT_HOST=livekit.example.com
    - LETSENCRYPT_EMAIL=you@example.com
  ports:
    - "7881:7881"       # TCP media fallback (direct, no TLS needed)
    - "7882:7882/udp"   # UDP RTP/RTCP media (direct, must stay open)
  volumes:
    - ./livekit-server.yaml:/config.yaml:ro
  depends_on:
    - redis
  networks:
    - proxy
    - internal

Meet backend configuration

LIVEKIT_API_URL serves dual purpose — it is used by the backend for server-to-server API calls AND returned to browser clients as the WebSocket URL. It must be the public WSS URL:

LIVEKIT_API_KEY=meetapikey
LIVEKIT_API_SECRET=your-livekit-api-secret
LIVEKIT_API_URL=wss://livekit.example.com

The backend resolves livekit.example.com via extra_hosts in the compose file:

meet-app:
  extra_hosts:
    - "livekit.example.com:host-gateway"

Do not use http://livekit:7880 for LIVEKIT_API_URL. That Docker-internal address is returned to browser clients who cannot resolve it.

Firewall requirements

Port Protocol Purpose
443 TCP LiveKit WebSocket via nginx-proxy (already open)
7881 TCP LiveKit TCP media fallback
7882 UDP LiveKit RTP/RTCP media (critical)

Port 7880 no longer needs to be open on the host firewall.

Verifying the setup

# Check LiveKit is reachable via HTTPS/WSS (after cert is issued)
curl -s -o /dev/null -w "%{http_code}" https://livekit.example.com/
# Expected: 200

# Test with LiveKit CLI
lk room list \
  --url wss://livekit.example.com \
  --api-key meetapikey \
  --api-secret your-secret

LiveKit Egress (for recording)

LiveKit Egress is a separate service required for recording. See Advanced: Recording & Transcription.

Production tips

  • Run LiveKit on a server with sufficient bandwidth — it forwards all media streams
  • Monitor LiveKit memory and CPU — each participant track consumes resources
  • Keep the LiveKit API secret 32+ characters and treat it like a database password
  • The UDP buffer warning (UDP receive buffer is too small) is informational — set net.core.rmem_max=5000000 on the host for production