name: siteforge-v8-10 # pinned: existing volumes with production data follow this project name services: siteforge: build: context: . dockerfile: Dockerfile args: SITEFORGE_GIT_SHA: ${SITEFORGE_GIT_SHA:-unknown} image: siteforge/web:8.21.3-dev.1 init: true restart: unless-stopped ports: - "127.0.0.1:${SITEFORGE_PORT:-8787}:8787" environment: SITEFORGE_DATA_DIR: /data SITEFORGE_MAX_PENDING_JOBS: ${SITEFORGE_MAX_PENDING_JOBS:-100} SITEFORGE_MAX_PENDING_JOBS_PER_SITE: ${SITEFORGE_MAX_PENDING_JOBS_PER_SITE:-5} SITEFORGE_OUTBOUND_PORTS: ${SITEFORGE_OUTBOUND_PORTS:-80,443} SITEFORGE_BUILD_TIMEOUT_SECONDS: ${SITEFORGE_BUILD_TIMEOUT_SECONDS:-300} SITEFORGE_MYSQL_ALLOWED_HOSTS: ${SITEFORGE_MYSQL_ALLOWED_HOSTS:-} SITEFORGE_MYSQL_ALLOWED_TABLES: ${SITEFORGE_MYSQL_ALLOWED_TABLES:-} SITEFORGE_ADMIN_PASSWORD: ${SITEFORGE_ADMIN_PASSWORD:?Set SITEFORGE_ADMIN_PASSWORD in .env} SITEFORGE_SESSION_SECRET: ${SITEFORGE_SESSION_SECRET:?Set SITEFORGE_SESSION_SECRET in .env} SITEFORGE_COOKIE_SECURE: "${SITEFORGE_COOKIE_SECURE:-false}" SITEFORGE_DEPLOY_STAGING_URL: ${SITEFORGE_DEPLOY_STAGING_URL:-} SITEFORGE_DEPLOY_STAGING_SECRET_REF: ${SITEFORGE_DEPLOY_STAGING_SECRET_REF:-} SITEFORGE_DEPLOY_PRODUCTION_URL: ${SITEFORGE_DEPLOY_PRODUCTION_URL:-} SITEFORGE_DEPLOY_PRODUCTION_SECRET_REF: ${SITEFORGE_DEPLOY_PRODUCTION_SECRET_REF:-} SITEFORGE_PUBLISH_ROOT: /published SITEFORGE_REQUIRE_RELEASE_APPROVAL: "true" volumes: - siteforge_data:/data - siteforge_published:/published read_only: true tmpfs: - /tmp:size=128m,mode=1777 security_opt: - no-new-privileges:true cap_drop: - ALL pids_limit: 128 healthcheck: test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8787/api/ready', timeout=3)"] interval: 30s timeout: 5s retries: 3 start_period: 30s worker: image: siteforge/web:8.21.3-dev.1 depends_on: siteforge: {condition: service_started} init: true restart: unless-stopped command: ["python", "-m", "app.worker"] environment: SITEFORGE_DATA_DIR: /data SITEFORGE_MAX_PENDING_JOBS: ${SITEFORGE_MAX_PENDING_JOBS:-100} SITEFORGE_MAX_PENDING_JOBS_PER_SITE: ${SITEFORGE_MAX_PENDING_JOBS_PER_SITE:-5} SITEFORGE_OUTBOUND_PORTS: ${SITEFORGE_OUTBOUND_PORTS:-80,443} SITEFORGE_MYSQL_ALLOWED_HOSTS: ${SITEFORGE_MYSQL_ALLOWED_HOSTS:-} SITEFORGE_MYSQL_ALLOWED_TABLES: ${SITEFORGE_MYSQL_ALLOWED_TABLES:-} SITEFORGE_MYSQL_CA_FILE: ${SITEFORGE_MYSQL_CA_FILE:-} # Development-only env secret references; use compose.mysql-secrets.yaml for production files. SITEFORGE_MYSQL_READ_USER: ${SITEFORGE_MYSQL_READ_USER:-} SITEFORGE_MYSQL_READ_PASSWORD: ${SITEFORGE_MYSQL_READ_PASSWORD:-} SITEFORGE_DEPLOY_STAGING_URL: ${SITEFORGE_DEPLOY_STAGING_URL:-} SITEFORGE_DEPLOY_STAGING_SECRET_REF: ${SITEFORGE_DEPLOY_STAGING_SECRET_REF:-} SITEFORGE_DEPLOY_PRODUCTION_URL: ${SITEFORGE_DEPLOY_PRODUCTION_URL:-} SITEFORGE_DEPLOY_PRODUCTION_SECRET_REF: ${SITEFORGE_DEPLOY_PRODUCTION_SECRET_REF:-} SITEFORGE_STAGING_TOKEN: ${SITEFORGE_STAGING_TOKEN:-} SITEFORGE_PRODUCTION_TOKEN: ${SITEFORGE_PRODUCTION_TOKEN:-} SITEFORGE_JOB_POLL_SECONDS: "1.5" SITEFORGE_BUILD_TIMEOUT_SECONDS: "${SITEFORGE_BUILD_TIMEOUT_SECONDS:-300}" SITEFORGE_BUILD_MAX_ATTEMPTS: "${SITEFORGE_BUILD_MAX_ATTEMPTS:-3}" volumes: - siteforge_data:/data read_only: true tmpfs: - /tmp:size=128m,mode=1777 security_opt: - no-new-privileges:true cap_drop: - ALL pids_limit: 128 healthcheck: test: ["CMD", "python", "-m", "app.worker_health"] interval: 20s timeout: 5s retries: 3 start_period: 30s volumes: siteforge_data: siteforge_published: