steep-balloon-41261
02/25/2026, 7:25 PMtall-airline-16756
02/25/2026, 7:25 PMtall-airline-16756
02/25/2026, 7:26 PMdocker-compose.yml and livekit.yaml. To make the guidance practical, I’ve provided minimal working examples below and a few follow-up questions so I can tailor them to your environment.
Minimal docker-compose + livekit.yaml examples (working starting point)
1) docker-compose.yml
• Runs the LiveKit server container.
• Optionally includes an nginx container for TLS termination.
version: '3.8'
services:
livekit:
image: livekit/livekit-server:latest
ports:
- "7880:7880" # WebSocket / signaling
- "7881:7881" # HTTP (health, metrics, etc.)
- "7882:7882/udp" # TURN / media UDP
volumes:
- ./livekit.yaml:/etc/livekit/livekit.yaml
- ./certs:/etc/letsencrypt # optional if handling TLS in the server
environment:
- LIVEKIT_KEYS=your-api-key:your-api-secret
- PORT=7880
command: ["--config", "/etc/livekit/livekit.yaml"]
restart: unless-stopped
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./certs:/etc/letsencrypt
depends_on:
- livekit
restart: unless-stopped
Notes:
• Replace your-api-key:your-api-secret with the key/secret you generate.
• Keep livekit ports exposed as above; UDP port 7882 is typical for TURN/media traffic.
• If you do TLS at the reverse proxy (nginx), you can keep LiveKit serving HTTP internally and terminate TLS in nginx.
2) livekit.yaml
• Minimal config to get the server running, enable TURN, and set keys.
bind_address: 0.0.0.0
port: 7880
# TURN (recommended for NAT traversal)
turn_enabled: true
turn_username: livekit
turn_password: your-turn-password
external_tcp_ports:
- 7882
external_udp_ports:
- 7882
# Redis (add if you plan to scale / multiple nodes)
# redis:
# address: "redis:6379"
# API keys for JWT generation / auth
keys:
your-api-key: your-api-secret
# Logging
logging:
level: info
Notes:
• turn_password should be a secure secret. TURN helps with clients behind strict NAT/firewalls.
• For scaling to multiple servers, enable and point redis to your Redis instance.
• You can also configure TLS directly using tls_cert_file and tls_key_file if you do not use nginx.
Optional nginx.conf (for TLS termination and websocket proxying)
events { worker_connections 1024; }
http {
server {
listen 80;
server_name <http://livekit.example.com|livekit.example.com>;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name <http://livekit.example.com|livekit.example.com>;
ssl_certificate /etc/letsencrypt/live/livekit.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/livekit.example.com/privkey.pem;
location / {
proxy_pass <http://livekit:7880;>
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
How to run
1. Save docker-compose.yml, livekit.yaml (and nginx.conf if using nginx) in a directory.
2. Generate API key/secret and set them in docker-compose.yml and livekit.yaml.
3. Start containers:
◦ docker-compose up -d
1. Test a client connection to https://livekit.yourdomain.com (or your server IP and port if not using TLS)
Follow-up questions so I can tailor this to your needs
• Do you have a domain name and SSL certificates (Let’s Encrypt) or do you want LiveKit to handle TLS directly?
• Will this be a single-node deployment or do you plan to scale across multiple servers (so I can include Redis/etcd details)?
• Are you running on a cloud provider (AWS / GCP / Azure) or on-prem / VPS?
• Do you need TURN to be externalized (coturn) or are you fine using LiveKit’s built-in TURN support?
• Do you already have an API key/secret or would you like guidance to generate them safely?
If you tell me the answers to any of the above, I’ll provide a customized docker-compose.yml and livekit.yaml (including Redis, coturn, or direct TLS options) and the exact steps to generate secure keys.
Sources: Running LiveKit on AWS | Self-hosted deployments | LiveKit Documentation | Server-side | livekit/livekit_composite | DeepWikitall-airline-16756
02/25/2026, 7:35 PMversion: "3.8"
services:
livekit:
image: livekit/livekit-server:latest
container_name: livekit
command: ["--config", "/config/livekit.yaml"]
volumes:
- ./livekit.yaml:/config/livekit.yaml:ro
ports:
- "7880:7880" # LiveKit WS / HTTP
- "7881:7881" # TCP TURN (external TCP)
- "50000-60000:50000-60000/udp" # Media UDP port range (VERY IMPORTANT)
restart: unless-stopped
worker:
container_name: sunny-worker
build:
context: .
dockerfile: Dockerfile
environment:
- LIVEKIT_URL=<ws://livekit:7880>
- LIVEKIT_API_KEY=A****************d
- LIVEKIT_API_SECRET=R****************D
depends_on:
- livekit
restart: unless-stopped
Notes:
• I added :ro to the config volume for safety (read-only inside the container). Remove if you need write access.
• Use your actual API key/secret values (those placeholders should match the keys in livekit.yaml).
• Ensure your host firewall allows UDP 50000–60000 and TCP 7880/7881.
2) livekit.yaml
• Matches your single-node setup (no Redis).
• Sets the ports and UDP range you specified.
• Keeps keys section for JWT/API auth.
port: 7880
rtc:
tcp_port: 7881
port_range_start: 50000
port_range_end: 60000
# If your server is behind NAT, set `external_ip` to your public IP or domain.
# external_ip: "203.0.113.10"
# No redis section -> single-node / in-memory mode
keys:
A****************d: R****************D
# TURN (built-in)
turn_enabled: true
turn_username: livekit
turn_password: your-turn-password
logging:
level: info
Notes and recommendations
• TURN password: Replace your-turn-password with a secure secret. TURN helps clients behind strict NATs. If you prefer a dedicated coturn, I can show how to add it.
• external_ip: If your server is behind NAT (cloud VM), set external_ip to the public IP or a domain so clients get the right ICE candidates.
• TLS: Right now this setup serves unencrypted WS on port 7880. For production, terminate TLS with an nginx reverse proxy (or use tls_cert_file / tls_key_file in livekit.yaml). If you want, I can provide an nginx config snippet and a TLS setup.
• Scaling: If you later run multiple LiveKit nodes, add a Redis section and point all nodes to the same Redis instance.
• Health/metrics: For monitoring, consider exposing the metrics endpoint (default on port 7881 or configured in livekit.yaml) as needed.
Quick checks before you run
• Replace key/secret placeholders in both files with the exact same real values.
• Confirm no other service on the host uses UDP 50000–60000.
• Open the ports in your cloud/VPS firewall or host firewall.
• If you use a domain, decide whether to terminate TLS at nginx or in LiveKit.
If you’d like, tell me:
• Do you have a domain and want TLS via nginx (I’ll provide the nginx conf and cert steps), or do you want LiveKit to handle TLS directly?
• Is your server behind NAT (cloud VM) so I can advise on external_ip?
• Want me to add a coturn service to docker-compose instead of using built-in TURN?
I can update the files for any of the above and show the exact commands to run.millions-dog-30135
02/25/2026, 9:48 PMtall-airline-16756
02/25/2026, 9:49 PMturn_password in livekit.yaml is the shared secret LiveKit uses for its built-in TURN server (or the credential that LiveKit will provide to clients when using TURN). It authenticates clients that try to use the TURN relay so only authorized users can relay media through your server.
Is it mandatory?
• TURN itself is not strictly mandatory — LiveKit can work without TURN when clients can connect directly using ICE/STUN.
• However, a TURN relay is strongly recommended for reliable connectivity across a wide range of networks. If you enable turn_enabled: true, you should set a turn_password.
• If you do not enable TURN (or you run an external coturn and configure it separately), you do not need to set turn_password in LiveKit.
What to set it to
• Use a strong, random password. It can be any string — treat it like a secret.
• Example generation commands:
◦ OpenSSL:
openssl rand -base64 24
• Linux / macOS (more portable):
head -c 24 /dev/urandom | base64
• Put the generated string as the turn_password in livekit.yaml. Also ensure any clients or coturn (if external) use matching credentials or that LiveKit is configured to generate credentials for clients.
Quick example (in livekit.yaml)
turn_enabled: true
turn_username: livekit
turn_password: s3cure-rand-string-abc123==
When you might skip it
• If you have a reliable, open network and want to test basic functionality, you can leave TURN disabled for initial tests.
• If you plan to run a dedicated coturn server instead of LiveKit’s built-in TURN, you’ll configure coturn separately and do not need the built-in turn_password (unless you want LiveKit to use its own TURN).
If you want, I can:
• Generate a secure password for you and show the exact line to paste into livekit.yaml.
• Show how to add a coturn service to your docker-compose and wire it up instead of using built-in TURN.
Which would you prefer?millions-dog-30135
02/26/2026, 3:48 PMtall-airline-16756
02/26/2026, 3:49 PMmillions-dog-30135
02/26/2026, 3:54 PMtall-airline-16756
02/26/2026, 3:54 PMexport LIVEKIT_URL="<https://your-livekit-domain-or-ip:7880>"
export LIVEKIT_API_KEY="YOUR_API_KEY"
export LIVEKIT_API_SECRET="YOUR_API_SECRET"
# Create an inbound SIP trunk for your DID
lk sip inbound create \
--name "vicidial-trunk" \
--numbers "+18052226602" \
--auth-username "asterisk" \
--auth-password "some-strong-pass" \
--allowed-addresses "ASTERISK_IP_OR_PROVIDER_IP"
Notes:
• --allowed-addresses is useful if your provider/Asterisk will IP-authenticate. If they use username/password, set those credentials and allow any IP.
• If LiveKit CLI requires slightly different flags, I’ll adapt after you tell me which CLI version you have.
C. Create a dispatch rule
• Example to map calls to rooms with prefix "call":
lk sip dispatch create \
--trunk-id TRUNK_ID_RETURNED_FROM_PREVIOUS_COMMAND \
--room-prefix "call"
This rule makes an incoming call to +18052226602 route to a LiveKit room like "call-<something>" (you can customize how rooms are chosen).
D. Asterisk dialplan example to forward to LiveKit
• If Asterisk will send calls to LiveKit directly (SIP invite to LiveKit), use something like:
sip.conf (chan_sip example, adapt to your SIP driver)
[livekit]
type=friend
host=your.livekit.ip.or.domain
port=5060 ; adapt port if different
insecure=port,invite
context=from-livekit
disallow=all
allow=ulaw
extensions.conf
[from-vicidial]
exten => _X.,1,NoOp(Forwarding call to LiveKit)
same => n,Dial(SIP/livekit/${EXTEN})
same => n,Hangup()
• If LiveKit expects certain SIP headers or a specific username, set them in the Dial or trunk configuration.
E. Testing
1. From a PSTN phone call +18052226602 → Vicidial → Asterisk sends to LiveKit.
2. Watch LiveKit logs and worker logs — confirm the SIP INVITE reaches LiveKit and the dispatch rule routes to a room/worker.
3. If media fails, check external_ip in livekit.yaml, UDP port ranges (50000–60000) are open, and TURN is enabled (for NAT scenarios).
Important production tips
• Set external_ip in livekit.yaml to your server’s public IP or domain so ICE candidates are correct.
• Ensure UDP media port range is open in host firewall and cloud provider.
• Use TLS and SRTP where possible. If using TLS, Asterisk must be configured to send to LiveKit over TLS.
• If you run into NAT or media issues, enabling TURN and configuring a coturn or LiveKit’s TURN with secure password will help.
Next step — what I suggest right now
• Tell me whether you want me to show exact CLI/API commands with placeholders (so you can replace them with your keys), or if you’ll supply:
◦ The LiveKit API key/secret (if you want me to write exact commands with real values)
◦ The LiveKit server reachable URL (domain or IP)
◦ Whether Asterisk authenticates by IP or username/password
• I will then produce the precise CLI commands to create the SIP inbound trunk and dispatch rule and a tailored Asterisk dialplan snippet you can drop into your server.
If you prefer, I can give the full sequence of commands and the exact JSON/Python SDK calls (instead of CLI) so you can automate this from Vicidial/Asterisk. Which do you prefer?