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 accessor

How a deploy works

  1. Pulumi creates the network, firewall rules, a static public IP, and the VM.
  2. The LiveKit API key/secret are generated as Pulumi secrets; the Cloudflare token is stored encrypted in stack config.
  3. cloud-init renders the Docker Compose stack, Caddy config, and livekit.yaml onto the VM and starts it.
  4. Cloudflare DNS records (lk.* and turn.*) are created pointing at the VM's IP.
  5. 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.