Architecture
Infrastructure
Everything is provisioned as code with Pulumi (TypeScript). A single VM runs the LiveKit Docker stack, configured entirely by cloud-init on first boot.
Stack at a glance
Pulumi + TypeScriptCloudflare DNSDocker Composecloud-initLet's Encrypt TLSLiveKit v1.12.0RedisUbuntu 24.04 LTS
Repository layout
The provider-neutral logic lives in infra/shared and is imported verbatim by each cloud's stack:
repo structure
infra/
shared/ # cloud-neutral — single source of truth
livekit.ts # generates compose, Caddy, livekit.yaml
cloud-init.ts # builds the #cloud-config bootstrap
azure/ # Pulumi stack — LiveKit on an Azure VM
index.ts # RG, network, VM + Cloudflare DNS
src/config.ts # typed config accessor
gcp/ # Pulumi stack — LiveKit on Google Compute Engine
index.ts # VPC, firewall, VM + Cloudflare DNS
src/config.ts # typed config accessorHow a deploy works
- Pulumi creates the network, firewall rules, a static public IP, and the VM.
- The LiveKit API key/secret are generated as Pulumi secrets; the Cloudflare token is stored encrypted in stack config.
cloud-initrenders the Docker Compose stack, Caddy config, andlivekit.yamlonto the VM and starts it.- Cloudflare DNS records (
lk.*andturn.*) are created pointing at the VM's IP. - Caddy obtains TLS certificates automatically once DNS resolves.
Networking & security
- Firewall opens only what's needed:
443(TLS),80(ACME), UDP media ports, and SSH. - DNS records are unproxied so WebRTC's UDP path is preserved.
- Secrets never live in source — they're Pulumi-encrypted.
- SSH access is key-based.
Reproducible by design
Because the bootstrap is encoded in
cloud-init, rebuilding a VM from scratch reproduces an identical server — no manual setup steps.