name: kaledonya-clips # Copy .env.example to .env, fill it in, then: docker compose up -d # Data lives under ./data (database, clips, Caddy's certificates); intake's scratch space is the intake-work volume. services: zipline-db: image: postgres:16 restart: unless-stopped environment: POSTGRES_USER: zipline POSTGRES_PASSWORD: ${POSTGRESQL_PASSWORD:?missing in .env} POSTGRES_DB: zipline volumes: - ./data/pgdata:/var/lib/postgresql/data healthcheck: test: ["CMD", "pg_isready", "-U", "zipline"] interval: 10s timeout: 5s retries: 5 zipline: image: ghcr.io/diced/zipline:4.8.0 restart: unless-stopped environment: DATABASE_URL: postgres://zipline:${POSTGRESQL_PASSWORD}@zipline-db:5432/zipline CORE_SECRET: ${CORE_SECRET:?missing in .env} CORE_RETURN_HTTPS_URLS: "true" CORE_DEFAULT_DOMAIN: ${SITE_DOMAIN:?missing in .env} CORE_TRUST_PROXY: "true" FILES_ROUTE: / # clips live at https:/// FILES_DEFAULT_FORMAT: name FILES_MAX_FILE_SIZE: 5gb FILES_DEFAULT_EXPIRATION: ${CLIP_LIFETIME:-90d} FEATURES_USER_REGISTRATION: "false" # invite only: the admin makes accounts in the dashboard INVITES_ENABLED: "false" TASKS_THUMBNAILS_INTERVAL: ${THUMBNAIL_INTERVAL:-5m} # library thumbnails for new uploads (Zipline default: 30m) depends_on: zipline-db: condition: service_healthy volumes: - ./data/uploads:/zipline/uploads - ./data/public:/zipline/public - ./data/themes:/zipline/themes healthcheck: test: ["CMD", "wget", "-q", "--spider", "http://0.0.0.0:3000/api/healthcheck"] interval: 15s timeout: 2s retries: 2 intake: build: ./intake restart: unless-stopped # uploads, .mkv remuxing and Discord copies; ffmpeg uses up to 4 threads at low priority cpus: ${INTAKE_CPUS:-4} environment: ZIPLINE_URL: http://zipline:3000 MAX_BYTES: "5368709120" DELETES_AT: ${CLIP_LIFETIME:-90d} SITE_ORIGIN: https://${SITE_DOMAIN} UPLOAD_URL: ${UPLOAD_URL:-https://${SITE_DOMAIN}} SITE_NAME: ${SITE_NAME:-kaledonya clips} SERVER_NAME: ${SERVER_NAME:-the server} UPLOAD_HINT: ${UPLOAD_HINT:-Can't reach the upload server.} volumes: - intake-work:/work # uploads in progress, .mkv remuxing, Discord copies (a named volume, so uid 1000 can write) healthcheck: test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health')"] interval: 30s timeout: 5s retries: 3 depends_on: - zipline # Option A (default): Caddy on ports 80/443 with an automatic HTTPS certificate for SITE_DOMAIN. caddy: image: caddy:2 restart: unless-stopped profiles: ["caddy"] ports: - "80:80" - "443:443" environment: SITE_DOMAIN: ${SITE_DOMAIN} volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro - ./data/caddy:/data depends_on: - intake - zipline # Option B: a Cloudflare Tunnel instead of open ports (see README, "Cloudflare Tunnel"). cloudflared: image: cloudflare/cloudflared:2026.9.3 restart: unless-stopped profiles: ["tunnel"] command: tunnel --no-autoupdate run environment: TUNNEL_TOKEN: ${TUNNEL_TOKEN:-} depends_on: - intake - zipline volumes: intake-work: