services: caddy: # Use the latest official Caddy image image: caddy:latest # Docker Compose automatically generates container names: __ container_name: caddy # Fixed name used by Docker engine # Automatically restart unless manually stopped restart: unless-stopped ports: # Expose HTTP (ACME + redirect) - "80:80" # Expose HTTPS/WSS (frontend, backend, LiveKit) - "443:443" volumes: # Mount the Caddy config file read-only - ./Caddyfile:/etc/caddy/Caddyfile:ro # Caddy TLS certs (persistent Docker volume) - caddy_data:/data # Internal Caddy state/config - caddy_config:/config networks: # Attach to the shared "proxy" network - proxy gitea: # Official Gitea image with built-in Actions image: gitea/gitea:latest container_name: gitea # Fixed name used by Docker engine # Auto-restart service restart: unless-stopped environment: # Run Gitea as host user 1000 (prevents permission issues) - USER_UID=1000 # Same for group - USER_GID=1000 # Use SQLite (stored inside /data) - GITEA__database__DB_TYPE=sqlite3 # Location of the SQLite DB - GITEA__database__PATH=/data/gitea/gitea.db # Custom config directory - GITEA_CUSTOM=/data/gitea volumes: # Bind mount instead of Docker volume because: # - We want repos, configs, SSH keys, and SQLite DB **visible and editable** on host # - Easy backups (just copy `./gitea-data`) # - Easy migration # - Avoids losing data if Docker volumes are pruned - ./gitea-data:/data networks: - proxy ports: # SSH for Git operations mapped to host 2222 - "2222:22" gitea-runner: # Official Gitea Actions Runner image: gitea/act_runner:latest container_name: gitea-runner # Fixed name used by Docker engine restart: unless-stopped depends_on: # Runner requires Gitea to be available - gitea volumes: # Runner uses host Docker daemon to spin up job containers (Docker-out-of-Docker) - /var/run/docker.sock:/var/run/docker.sock # Bind mount instead of volume because: # - Runner identity is stored in /data/.runner # - Must persist across container recreations # - Prevents duplicated runner registrations in Gitea # - Easy to inspect/reset via `./gitea-runner-data/.runner` - ./gitea-runner-data:/data environment: # Base URL of your Gitea instance - GITEA_INSTANCE_URL=${GITEA_INSTANCE_URL} # One-time registration token - GITEA_RUNNER_REGISTRATION_TOKEN=${GITEA_RUNNER_REGISTRATION_TOKEN} # Human-readable name for the runner - GITEA_RUNNER_NAME=${GITEA_RUNNER_NAME} # Runner labels (e.g., ubuntu-latest) - GITEA_RUNNER_LABELS=${GITEA_RUNNER_LABELS} # Set container timezone to UTC for consistent logs - TZ=Etc/UTC networks: - proxy # Start runner using persisted config command: ["act_runner", "daemon", "--config", "/data/.runner"] networks: proxy: # Shared network for Caddy + Gitea (+ later app stack) name: proxy # Default Docker bridge network driver: bridge volumes: # Docker volume for Caddy TLS data (safe to keep inside Docker) caddy_data: name: caddy_data # Docker volume for internal Caddy configs/state caddy_config: name: caddy_config