# ============================================================================= # Forgejo Git Server - Docker Compose Stack # Forgejo 11.0.8 LTS with PostgreSQL, Caddy, and Actions Runner # ============================================================================= services: # --------------------------------------------------------------------------- # PostgreSQL Database # --------------------------------------------------------------------------- forgejo-db: image: postgres:16-alpine container_name: forgejo-db restart: unless-stopped environment: POSTGRES_USER: ${POSTGRES_USER:-forgejo} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD required} POSTGRES_DB: ${POSTGRES_DB:-forgejo} volumes: - /mnt/forgejo/forgejo-db:/var/lib/postgresql/data networks: - forgejo-internal healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-forgejo} -d ${POSTGRES_DB:-forgejo}"] interval: 10s timeout: 5s retries: 5 # --------------------------------------------------------------------------- # Forgejo Git Server # Using rootless image for better security # --------------------------------------------------------------------------- forgejo: image: codeberg.org/forgejo/forgejo:11.0.8-rootless container_name: forgejo restart: unless-stopped depends_on: forgejo-db: condition: service_healthy environment: # Database FORGEJO__database__DB_TYPE: postgres FORGEJO__database__HOST: forgejo-db:5432 FORGEJO__database__NAME: ${POSTGRES_DB:-forgejo} FORGEJO__database__USER: ${POSTGRES_USER:-forgejo} FORGEJO__database__PASSWD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD required} # Server configuration FORGEJO__server__DOMAIN: ${FORGEJO_DOMAIN:?FORGEJO_DOMAIN required} FORGEJO__server__ROOT_URL: https://${FORGEJO_DOMAIN}/ FORGEJO__server__SSH_DOMAIN: ${FORGEJO_DOMAIN} FORGEJO__server__SSH_PORT: 2222 FORGEJO__server__SSH_LISTEN_PORT: 2222 FORGEJO__server__START_SSH_SERVER: "true" FORGEJO__server__HTTP_PORT: 3000 FORGEJO__server__LFS_START_SERVER: "true" # Security FORGEJO__security__INSTALL_LOCK: "true" FORGEJO__security__SECRET_KEY: ${FORGEJO_SECRET_KEY:?FORGEJO_SECRET_KEY required} FORGEJO__security__INTERNAL_TOKEN: ${FORGEJO_INTERNAL_TOKEN:?FORGEJO_INTERNAL_TOKEN required} FORGEJO__security__PASSWORD_COMPLEXITY: "lower,upper,digit" FORGEJO__security__MIN_PASSWORD_LENGTH: "12" # OAuth2 JWT secret FORGEJO__oauth2__JWT_SECRET: ${FORGEJO_JWT_SECRET:?FORGEJO_JWT_SECRET required} # Service settings FORGEJO__service__DISABLE_REGISTRATION: "false" FORGEJO__service__REQUIRE_SIGNIN_VIEW: "false" FORGEJO__service__ENABLE_NOTIFY_MAIL: "false" # Actions (CI/CD) FORGEJO__actions__ENABLED: "true" FORGEJO__actions__DEFAULT_ACTIONS_URL: "https://code.forgejo.org" # Repository settings FORGEJO__repository__DEFAULT_BRANCH: "main" FORGEJO__repository__ENABLE_PUSH_CREATE_USER: "true" FORGEJO__repository__ENABLE_PUSH_CREATE_ORG: "true" # LFS settings FORGEJO__lfs__PATH: /data/lfs # Webhook settings (for CI/CD) FORGEJO__webhook__ALLOWED_HOST_LIST: "private" FORGEJO__webhook__SKIP_TLS_VERIFY: "false" # Log settings FORGEJO__log__MODE: "console" FORGEJO__log__LEVEL: "Info" volumes: - /mnt/forgejo/forgejo-data:/data - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro networks: - forgejo-internal - forgejo-public ports: # Git SSH - exposed publicly - "2222:2222" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3000/api/healthz"] interval: 30s timeout: 10s retries: 3 start_period: 60s # --------------------------------------------------------------------------- # Caddy Reverse Proxy # Automatic HTTPS with Let's Encrypt # --------------------------------------------------------------------------- caddy: image: caddy:2-alpine container_name: forgejo-caddy restart: unless-stopped depends_on: forgejo: condition: service_healthy ports: - "80:80" - "443:443" volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro - caddy_data:/data - caddy_config:/config networks: - forgejo-public environment: FORGEJO_DOMAIN: ${FORGEJO_DOMAIN} # --------------------------------------------------------------------------- # Forgejo Actions Runner # For CI/CD pipelines # --------------------------------------------------------------------------- forgejo-runner: image: code.forgejo.org/forgejo/runner:6.3.1 container_name: forgejo-runner restart: unless-stopped depends_on: forgejo: condition: service_healthy docker-dind: condition: service_started environment: DOCKER_HOST: tcp://docker-dind:2376 DOCKER_TLS_VERIFY: "1" DOCKER_CERT_PATH: /certs/client volumes: - /mnt/forgejo/runner-data:/data - dind-certs-client:/certs/client:ro networks: - forgejo-internal - dind-network command: > sh -c ' if [ ! -f /data/.runner ]; then echo "Runner not registered. Please run registration command first." echo "See README for registration instructions." sleep infinity fi forgejo-runner daemon --config /data/config.yaml ' # --------------------------------------------------------------------------- # Docker-in-Docker for Runner # Allows building Docker images in CI/CD # --------------------------------------------------------------------------- docker-dind: image: docker:27-dind container_name: forgejo-dind restart: unless-stopped privileged: true environment: DOCKER_TLS_CERTDIR: /certs volumes: - dind-certs-ca:/certs/ca - dind-certs-client:/certs/client - dind-storage:/var/lib/docker networks: - dind-network # Resource limits for 1GB RAM droplet deploy: resources: limits: memory: 512M # ============================================================================= # Networks # ============================================================================= networks: forgejo-internal: driver: bridge internal: true forgejo-public: driver: bridge dind-network: driver: bridge # ============================================================================= # Volumes # ============================================================================= volumes: caddy_data: caddy_config: dind-certs-ca: dind-certs-client: dind-storage: