Skip to main content

Overview

livekitctl is a purpose-built CLI tool that automates the installation and configuration of a complete LiveKit media server stack for Fluxer’s real-time voice and video communication.
livekitctl is designed for production deployments on Linux servers and handles TLS certificate provisioning, firewall configuration, and service orchestration automatically.

Stack Components

The tool deploys and configures:

LiveKit

WebRTC Selective Forwarding Unit (SFU) for scalable voice and video

Caddy

Reverse proxy with automatic TLS certificate management (built with L4 module)

coturn

TURN/STUN server for NAT traversal and firewall penetration

KV Store

Redis-compatible key-value store for LiveKit state management

Installation

Install livekitctl on your Linux server:
curl -fsSL https://fluxer.app/get/livekitctl | sudo bash
The installer:
  • Downloads the appropriate binary for your architecture
  • Installs to /usr/local/bin/livekitctl
  • Sets executable permissions
  • Verifies installation with version check

Prerequisites

1

Linux Server

Supported distributions:
  • Debian/Ubuntu
  • RHEL/CentOS/Rocky/Alma
  • Arch Linux
2

Root Access

Bootstrap requires root privileges for:
  • systemd service installation
  • Firewall configuration (optional)
  • Binary installation to /opt/livekit
3

DNS Configuration

Configure A/AAAA records pointing to your server’s public IP:
A    livekit.example.com  →  203.0.113.10
A    turn.example.com     →  203.0.113.10
AAAA livekit.example.com  →  2001:db8::1
AAAA turn.example.com     →  2001:db8::1
DNS records must propagate before bootstrap runs. The tool waits up to 15 minutes for DNS to resolve.

Commands

bootstrap

Install and configure the complete LiveKit stack.
livekitctl bootstrap \
  --livekit-domain livekit.example.com \
  --turn-domain turn.example.com \
  --email [email protected]

Required Flags

--livekit-domain
string
required
Fully qualified domain name for LiveKit WebSocket/HTTP connections. Must have valid DNS A/AAAA records.
--turn-domain
string
required
Fully qualified domain name for TURN relay server. Should be different from LiveKit domain.
--email
string
required
Email address for ACME TLS certificate registration (Let’s Encrypt notifications).

Optional Flags

--livekit-version
string
default:"v1.9.11"
LiveKit server version to install. See LiveKit releases.
--caddy-version
string
default:"v2.10.2"
Caddy version to build with xcaddy.
--caddy-l4-version
string
default:"master"
Caddy Layer 4 module version for TCP/UDP proxying.
--xcaddy-version
string
default:"v0.4.5"
xcaddy build tool version.
--install-dir
string
default:"/opt/livekit"
Custom installation directory for LiveKit binaries.
--firewall
boolean
Automatically configure detected firewall (ufw, firewalld, or iptables) to allow required ports.
--kv-port
number
default:"6379"
Port for the KV store (Redis-compatible). Binds to localhost only.
--kv-port-auto
boolean
Automatically select an available port from 6379-6382.
--webhook-url
string
LiveKit webhook URL for room events. Can be specified multiple times.
--webhook-urls-file
string
File containing webhook URLs (one per line).
--allow-http-webhooks
boolean
Allow insecure HTTP webhook URLs (not recommended for production).
--dns-timeout
number
default:"900"
Maximum seconds to wait for DNS propagation before failing.
--dns-interval
number
default:"10"
Seconds between DNS propagation checks.
--print-secrets
boolean
Print generated API keys and secrets as JSON to stdout after bootstrap.

status

Display systemd service status for all managed services.
livekitctl status
livekitctl status output
Shows:
  • Service name and unit file
  • Active/inactive state
  • Running/failed status
  • Memory and CPU usage
  • Recent log entries

logs

View systemd journal logs for a specific service.
# View LiveKit logs (last 200 lines)
livekitctl logs --service livekit.service

# View more lines
livekitctl logs --service livekit.service --lines 1000

# View Caddy logs
livekitctl logs --service caddy.service --lines 500
--service
string
required
systemd unit name:
  • livekit-kv.service - KV store
  • livekit-coturn.service - TURN server
  • livekit.service - LiveKit SFU
  • caddy.service - Reverse proxy
--lines
number
default:"200"
Number of log lines to display.

restart

Restart one or more services.
# Restart all services
livekitctl restart

# Restart specific service
livekitctl restart livekit.service

# Restart multiple services
livekitctl restart caddy.service livekit.service
Restart order is automatically determined based on service dependencies. The KV store starts first, followed by coturn, LiveKit, and finally Caddy.

webhook

Manage LiveKit webhook URLs for room events.
livekitctl webhook list
Webhook changes automatically restart the LiveKit service to apply the new configuration.

Port Configuration

Default port allocations:
PortProtocolServiceFirewall
7880TCPLiveKit HTTP (internal, proxied by Caddy)
7881TCPLiveKit RTC signaling
50000-60000UDPLiveKit RTC media
3478UDPTURN/STUN listen
40000-49999UDPTURN relay ports
6379TCPKV store (localhost only)
80TCPCaddy HTTP (ACME challenge)
443TCPCaddy HTTPS
If using the --firewall flag, livekitctl automatically configures your firewall to allow required ports.

State and Configuration Files

livekitctl stores state and configuration in /etc/livekit/:
/etc/livekit/
├── livekitctl-state.json      # Bootstrap state and metadata
├── secrets.json               # API keys, secrets (chmod 600)
├── livekit.yaml               # LiveKit server configuration
├── caddy.json                 # Caddy reverse proxy config
└── coturn.conf                # TURN server configuration

/opt/livekit/
└── bin/
    └── livekit-server         # LiveKit binary

Secrets File Format

The secrets.json file contains:
{
  "api_key": "APIxxxxxxxxx",
  "api_secret": "secret-key-here",
  "turn_shared_secret": "turn-auth-secret"
}
Keep secrets.json secure! It contains credentials for LiveKit API access and TURN authentication.

Global Flags

--state
string
default:"/etc/livekit/livekitctl-state.json"
Path to state file. Use a custom path for multiple LiveKit deployments on the same server.

Troubleshooting

Problem: Bootstrap fails with “DNS records not found”Solution:
  1. Verify DNS records with dig:
    dig +short livekit.example.com
    dig +short turn.example.com
    
  2. Increase timeout:
    livekitctl bootstrap --dns-timeout 3600 ...
    
  3. Wait for global DNS propagation (can take hours)
Problem: “bind: address already in use”Solution:
  1. Check what’s using the port:
    sudo lsof -i :6379
    sudo ss -tulpn | grep 6379
    
  2. Use auto port selection:
    livekitctl bootstrap --kv-port-auto ...
    
  3. Specify custom port:
    livekitctl bootstrap --kv-port 6380 ...
    
Problem: Caddy fails to obtain TLS certificateSolution:
  1. Verify DNS points to server:
    curl -I http://livekit.example.com
    
  2. Check firewall allows port 80:
    sudo ufw status
    sudo firewall-cmd --list-all
    
  3. Review Caddy logs:
    livekitctl logs --service caddy.service --lines 500
    
Problem: Service remains inactive after restartSolution:
  1. Check service status:
    sudo systemctl status livekit.service
    
  2. View full logs:
    sudo journalctl -u livekit.service -n 100 --no-pager
    
  3. Verify configuration:
    cat /etc/livekit/livekit.yaml
    
  4. Test binary manually:
    /opt/livekit/bin/livekit-server --config /etc/livekit/livekit.yaml
    

Best Practices

Use Separate Domains

Keep LiveKit and TURN on different subdomains for better routing and debugging.livekit.fluxer.app + turn.fluxer.applivekit.fluxer.app for both

Monitor Webhooks

Configure webhooks to track room events, participant joins/leaves, and detect issues.

Regular Updates

Keep LiveKit and Caddy updated for security patches and performance improvements.
livekitctl bootstrap \
  --livekit-version v1.10.0 \
  ... # other flags

Backup Secrets

Store /etc/livekit/secrets.json in a secure location (password manager, vault).

Integration with Fluxer

After bootstrap, configure Fluxer to use your LiveKit server:
config/config.json
{
  "livekit": {
    "url": "wss://livekit.example.com",
    "apiKey": "APIxxxxxxxxx",
    "apiSecret": "secret-from-secrets-json"
  }
}
The LiveKit server will:
  • Accept WebRTC connections from Fluxer clients
  • Send room events to configured webhook URLs
  • Handle voice/video routing with automatic quality adaptation
  • Provide TURN relay for clients behind restrictive NAT

See Also

Build docs developers (and LLMs) love