Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

LiveKit Server — GCP VM Deploy

Fork/adaptation of livekit/livekit focused on self-hosting the LiveKit Server on a Google Cloud Platform (GCP) VM.

This repository does not contain the Go source code of the SFU. It packages the official configuration (Docker + Caddy + Redis) with GCP scripts, based on the workflow recommended by the LiveKit documentation for VMs.

What's included

  • docker-compose.yaml — LiveKit Server, Redis, Caddy, and Token Server
  • config/ — configuration templates with placeholders
  • token-server/ — API for automatic JWT token generation
  • scripts/gcp/ — VM creation, firewall, and cloud-init
  • systemd/livekit-docker.service — automatic startup on the VM

Prerequisites

Local (dev):

  • Linux (docker-compose uses network_mode: host — does not work on Docker Desktop for Mac/Windows)
  • Docker + Docker Compose
  • Free ports: 7880, 6379, 3001 (and UDP 50000–60000 for WebRTC media)

GCP (production):

  1. GCP account with billing enabled
  2. Google Cloud SDK (gcloud) installed and authenticated
  3. Two DNS records pointing to the VM's IP:
    • livekit.yourdomain.com — WebSocket signaling (WSS)
    • livekit-turn.yourdomain.com — TURN/TLS

Running locally

Full workflow for testing on your machine without Caddy/TLS.

1. Configure variables

cp .env.example .env

Edit .env with your credentials and local URLs:

LIVEKIT_API_KEY=APIxxxxx
LIVEKIT_API_SECRET=your_secret_here
LIVEKIT_URL=ws://localhost:7880
TOKEN_SERVER_PORT=3001
CORS_ORIGIN=http://localhost:3000

Use ws:// (no TLS) for local. If the frontend runs on a different port (e.g., Vue CLI on 8080), set CORS_ORIGIN to the exact browser origin (http://localhost:8080). localhost and 127.0.0.1 are different origins for CORS.

If you don't have an API key/secret yet:

chmod +x scripts/*.sh
./scripts/generate-keys.sh

2. Adjust LiveKit for the local environment

In config/livekit.yaml.template, change:

rtc:
  use_external_ip: false   # true only on GCP

Optional (simplifies local testing):

turn:
  enabled: false

Generate the configuration files:

./scripts/configure.sh

Required before starting Docker. This script reads .env and generates livekit.yaml and caddy.yaml in the project root from the templates in config/. The docker-compose.yaml mounts these two files into the containers — without them, the livekit and caddy services won't start. Run it again whenever you change .env or the templates in config/.

3. Start the services

docker compose up redis livekit token-server -d

Check status and logs:

docker compose ps
docker compose logs -f livekit
docker compose logs -f token-server

4. Test the token server

curl http://localhost:3001/health

curl "http://localhost:3001/api/connection-details?roomName=test&participantName=Joao&identity=user-1&accessLevel=0"

The response should include serverUrl, roomName, participantName, and participantToken.

Test CORS (replace with your frontend's origin):

curl -i -H "Origin: http://localhost:3000" \
  "http://localhost:3001/api/connection-details?roomName=test&participantName=Joao"

The Access-Control-Allow-Origin header must match the CORS_ORIGIN from .env.

5. Connect the client (RUXAILAB)

In the RUXAILAB project's .env:

VUE_APP_LIVEKIT_ENABLED=true
VUE_APP_LIVEKIT_TOKEN_SERVER_URL=http://localhost:3001
VUE_APP_LIVEKIT_URL=ws://localhost:7880

The client fetches tokens automatically from GET /api/connection-details — no need to use livekit-cli.

6. Connect LiveKit Meet (optional)

In the meet project, configure .env.local:

LIVEKIT_API_KEY=<same key>
LIVEKIT_API_SECRET=<same secret>
LIVEKIT_URL=ws://localhost:7880
NEXT_PUBLIC_CONN_DETAILS_ENDPOINT=http://localhost:3001/api/connection-details
cd ../meet && pnpm install && pnpm dev

Useful Docker commands (local)

# Stop everything
docker compose down

# Start again
docker compose up redis livekit token-server -d

# Restart a service (after changing .env)
docker compose restart token-server

# Rebuild token-server (after changing code or .env)
docker compose up token-server -d --build --force-recreate

# Live logs
docker compose logs -f token-server

Running the token-server without Docker

cd token-server
npm install

# Load variables from the project root .env
export $(grep -v '^#' ../.env | xargs)
npm run dev

Quick start (GCP)

1. Configure variables

cp .env.example .env

Edit .env with your domain, GCP project, and zone.

2. Generate API Key / Secret

chmod +x scripts/*.sh scripts/gcp/*.sh
./scripts/generate-keys.sh

Copy the key and secret into .env:

LIVEKIT_API_KEY=APIxxxxx
LIVEKIT_API_SECRET=your_secret_here

3. Render configs

./scripts/configure.sh

Required. Generates livekit.yaml and caddy.yaml in the project root from the templates in config/. These files are mounted by docker-compose.yaml (and shipped to the VM via cloud-init), so they must exist before starting the services. Run it again whenever you change .env or the templates.

4. Create the VM on GCP (automatic)

./scripts/gcp/create-vm.sh

The script:

  1. Creates firewall rules (TCP 80/443/7881, UDP 3478, UDP 50000–60000)
  2. Reserves a static IP
  3. Creates the Ubuntu 22.04 VM with cloud-init
  4. Installs Docker and starts LiveKit via systemd

5. Connect clients

In the meet project, configure .env.local:

LIVEKIT_API_KEY=<same key>
LIVEKIT_API_SECRET=<same secret>
LIVEKIT_URL=wss://livekit.yourdomain.com
NEXT_PUBLIC_CONN_DETAILS_ENDPOINT=https://livekit.yourdomain.com/api/connection-details

In production, expose the token-server behind Caddy or a reverse proxy with HTTPS.

Token server (API)

Node.js service that generates JWTs automatically — replaces manual use of livekit-cli.

Endpoint

GET /api/connection-details?roomName=<room>&participantName=<name>&identity=<id>&accessLevel=<0-3>
Parameter Required Description
roomName yes Room name/ID (in RUXAILAB: testId)
participantName yes Participant's display name
identity no Stable participant ID (RUXAILAB: userId). If omitted, generates participantName__<suffix> via cookie (compatible with LiveKit Meet)
accessLevel no RUXAILAB role: 0 moderator, 1 evaluator, 2 participant, 3 observer. Omit = full publish (Meet / legacy)
metadata no Optional metadata attached to the JWT token

LiveKit grants by accessLevel (RUXAILAB):

accessLevel Role canPublish canSubscribe canPublishData
0 Moderator
1 Evaluator
2 Participant
3 Observer
omitted Meet / legacy

Also available: GET /health{ "status": "ok" }.

Response:

{
  "serverUrl": "ws://localhost:7880",
  "roomName": "my-room",
  "participantName": "João",
  "participantToken": "eyJ..."
}

Manual VM deploy

If you prefer to provision the VM yourself:

./scripts/configure.sh
scp -r . user@VM_IP:/opt/livekit/
ssh user@VM_IP 'cd /opt/livekit && sudo ./scripts/install.sh'

Firewall ports (GCP)

Port Protocol Use
80 TCP ACME / Let's Encrypt
443 TCP WSS + TURN/TLS
7881 TCP WebRTC fallback (ICE/TCP)
3478 UDP TURN/UDP
50000–60000 UDP WebRTC media

In config/livekit.yaml.template, use use_external_ip: true on GCP and false locally.

Useful commands on the VM

# Service status
sudo systemctl status livekit-docker

# Logs
sudo docker compose -f /opt/livekit/docker-compose.yaml logs -f

# Restart
sudo systemctl restart livekit-docker

Testing the connection (optional — CLI)

For manual debugging, without the token server:

curl -sSL https://get.livekit.io/cli | bash

Generate a test token:

livekit-cli create-token \
  --api-key "$LIVEKIT_API_KEY" \
  --api-secret "$LIVEKIT_API_SECRET" \
  --join --room test-room --identity user1 \
  --valid-for 24h

Upstream

License

The configuration follows the Apache 2.0 license of the LiveKit project.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages