This guide covers setting up a LiveKit server on an Ubuntu VPS for use with DEN Chat voice channels. LiveKit includes a built-in TURN relay, so no separate TURN server (coturn, etc.) is needed.
Requirements:
- Ubuntu VPS (BitLaunch, Hetzner, etc.)
- A domain name pointed at your server (Let's Encrypt does not issue certs for bare IPs)
- Root/sudo access
1. Provision your VPS
Minimum specs (testing)
- 1 vCPU, 1 GB RAM, 25 GB SSD
Recommended specs (production)
- 2-4 vCPU, 4-8 GB RAM
WebRTC is network-heavy, not disk-heavy. Prioritize bandwidth over storage.
2. Point a domain at your server
You need a domain because browsers block insecure WebSocket connections (ws://) from HTTPS pages. TLS requires a certificate, and Let's Encrypt does not issue certificates for bare IP addresses.
If you don't have a domain, free options work fine:
- DuckDNS — free subdomains like
yourname.duckdns.org - FreeDNS (afraid.org) — free subdomains on various domains
In your DNS provider, create an A record pointing to your server's IP:
| Type | Name | Value |
|---|---|---|
| A | lk | YOUR_SERVER_IP |
This gives you lk.yourdomain.com. DNS propagation can take a few minutes to a few hours. Verify it's ready before continuing:
nslookup lk.yourdomain.com
You should see your server's IP in the response. If not, wait and try again.
3. Connect and install dependencies
ssh root@YOUR_SERVER_IP
apt update && apt upgrade -y
apt install -y curl openssl ufw
4. Install LiveKit Server
curl -sSL https://get.livekit.io | bash
Verify:
livekit-server --version
5. Generate an API key and secret
openssl rand -hex 32
Save the output — this is your API secret. Choose an API key name (any string, e.g. myapikey).
6. Create the LiveKit config
nano livekit.yaml
port: 7880
rtc:
tcp_port: 7881
port_range_start: 50000
port_range_end: 60000
use_ice_lite: true
use_external_ip: true
turn:
enabled: true
domain: lk.yourdomain.com
udp_port: 3478
tls_port: 0
keys:
myapikey: YOUR_SECRET_HERE
Replace lk.yourdomain.com with your actual domain, myapikey with your key name, and YOUR_SECRET_HERE with the secret from step 5.
The turn block enables LiveKit's built-in TURN relay over UDP. No external TURN server is needed. WebSocket encryption (WSS) is handled by Caddy separately.
7. Install Caddy (TLS reverse proxy)
Caddy provides automatic HTTPS with Let's Encrypt — no manual certificate management.
apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list
apt update
apt install caddy
Create the Caddy config:
nano /etc/caddy/Caddyfile
lk.yourdomain.com {
reverse_proxy localhost:7880
}
Replace lk.yourdomain.com with your domain. Start Caddy:
systemctl restart caddy
Caddy will automatically obtain and renew the TLS certificate.
8. Open firewall ports
ufw allow 22/tcp # SSH
ufw allow 80/tcp # Caddy (Let's Encrypt HTTP challenge)
ufw allow 443/tcp # Caddy (WSS)
ufw allow 7881/tcp # RTC over TCP
ufw allow 3478/udp # TURN (UDP)
ufw allow 50000:60000/udp # WebRTC media
ufw enable
9. Start LiveKit
Test run (foreground):
livekit-server --config livekit.yaml
Leave it running and open a second SSH session to your server. Verify locally:
curl http://127.0.0.1:7880
Expected output: OK
Verify through Caddy:
curl https://lk.yourdomain.com
Should also return OK. If it does, TLS is working.
Once verified, go back to the first SSH session and press Ctrl+C to stop the foreground process.
10. Run LiveKit as a service
LiveKit needs to run permanently in the background — surviving SSH disconnects and server reboots. Create a systemd service for this:
nano /etc/systemd/system/livekit.service
Paste the following:
[Unit]
Description=LiveKit Server
After=network.target
[Service]
ExecStart=/usr/local/bin/livekit-server --config /root/livekit.yaml
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
Save and exit (Ctrl+X, then Y, then Enter). Then enable and start it:
systemctl enable livekit
systemctl start livekit
Verify it's running:
systemctl status livekit
You should see active (running). From now on, LiveKit starts automatically on boot and restarts if it crashes.
11. Configure DEN Chat
In your hub settings, set the voice provider to LiveKit and enter:
| Field | Value |
|---|---|
| Server URL | wss://lk.yourdomain.com |
| API Key | myapikey |
| API Secret | The secret from step 5 |
DEN Chat handles token generation and TURN relay configuration automatically.
12. Verify
LiveKit server:
curl https://lk.yourdomain.com
Should return OK.
Voice channel: Join a voice channel in DEN Chat. If you hear audio, it's working.
TURN relay: Confirm via chrome://webrtc-internals — look for relay candidates in the ICE connection log after joining a voice channel.
Rotating credentials
If a member leaves your hub and you want to prevent them from using your LiveKit server, rotate your API secret:
- Generate a new secret:
openssl rand -hex 32
- Update
livekit.yamlwith the new secret:
nano livekit.yaml
Replace the old secret in the keys: section with the new one. Save and exit (Ctrl+X, then Y, then Enter).
- Restart LiveKit:
systemctl restart livekit
- Update your DEN Chat hub settings with the new API secret.
The old secret is immediately invalidated. Any tokens generated with the old secret will be rejected.