# PRODUCTION single-node stack: Caddy (automatic HTTPS) + Tilework + LiveKit. # 1) cp deploy/.env.example deploy/.env and fill it in (the file refuses to start without the required values) # 2) create the first admin invite: docker compose run --rm tilework -invite admin # 3) docker compose up -d --build name: tilework services: tilework: # Prebuilt multi-arch image (amd64/arm64) published by .github/workflows/docker.yml. "--build" builds locally. image: "${TILEWORK_IMAGE:-ghcr.io/guhcostan/tilework:latest}" build: { context: .., dockerfile: deploy/Dockerfile } restart: unless-stopped environment: TILEWORK_ENV: production TILEWORK_ADDR: ":8080" TILEWORK_DB: "${TILEWORK_DB:-/data/tilework.db}" TILEWORK_ALLOWED_ORIGINS: "${APP_DOMAIN:?set APP_DOMAIN}" TILEWORK_OFFICE_NAME: "${OFFICE_NAME:-Office}" TILEWORK_METRICS_TOKEN: "${METRICS_TOKEN:-}" # Public sandbox (see deploy/README.md "Public demo"): invite-less member joins, content reset every N hours. TILEWORK_DEMO: "${DEMO:-}" TILEWORK_DEMO_RESET_HOURS: "${DEMO_RESET_HOURS:-6}" TILEWORK_MAX_PLAYERS: "${MAX_PLAYERS:-2000}" TILEWORK_SESSION_DAYS: "${SESSION_DAYS:-30}" LIVEKIT_URL: "wss://${LIVEKIT_DOMAIN:?set LIVEKIT_DOMAIN}" LIVEKIT_API_URL: http://livekit:7880 LIVEKIT_API_KEY: "${LIVEKIT_API_KEY:?set LIVEKIT_API_KEY}" LIVEKIT_API_SECRET: "${LIVEKIT_API_SECRET:?set LIVEKIT_API_SECRET (>= 32 chars)}" volumes: ["tilework-data:/data"] healthcheck: test: ["CMD", "/app/tilework", "-healthcheck"] interval: 15s timeout: 5s retries: 3 expose: ["8080"] depends_on: [livekit] livekit: image: livekit/livekit-server:v1.13.7 restart: unless-stopped environment: LIVEKIT_KEYS: "${LIVEKIT_API_KEY}: ${LIVEKIT_API_SECRET}" LIVEKIT_CONFIG: | port: 7880 log_level: info rtc: tcp_port: 7881 udp_port: 7882 use_external_ip: true turn: enabled: true domain: ${LIVEKIT_DOMAIN} udp_port: 3478 external_tls: false ports: - "7881:7881" # ICE/TCP fallback - "7882:7882/udp" # media (single UDP port) - "3478:3478/udp" # TURN/UDP expose: ["7880"] # signalling, reached through Caddy (wss) caddy: image: caddy:2 restart: unless-stopped ports: ["80:80", "443:443"] environment: APP_DOMAIN: "${APP_DOMAIN}" LIVEKIT_DOMAIN: "${LIVEKIT_DOMAIN}" volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro - caddy-data:/data - caddy-config:/config depends_on: [tilework, livekit] volumes: tilework-data: name: "${TILEWORK_DATA_VOLUME:-${COMPOSE_PROJECT_NAME:-tilework}_tilework-data}" caddy-data: name: "${TILEWORK_CADDY_DATA_VOLUME:-${COMPOSE_PROJECT_NAME:-tilework}_caddy-data}" caddy-config: name: "${TILEWORK_CADDY_CONFIG_VOLUME:-${COMPOSE_PROJECT_NAME:-tilework}_caddy-config}"