# FreeTable Coolify Deployment Configuration # Production stack: Backend (FastAPI+Gunicorn) + Frontend (Nginx) + PostgreSQL x-common-env: &common-env TZ: ${TZ:-UTC} LOG_LEVEL: ${LOG_LEVEL:-INFO} x-backend-base: &backend-base build: context: . dockerfile: Dockerfile restart: unless-stopped depends_on: db: condition: service_healthy networks: - freetable-network x-healthcheck-backend: &healthcheck-backend healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/health"] interval: 30s timeout: 10s retries: 3 start_period: 30s services: # ==================== PostgreSQL Database ==================== db: image: postgres:16-alpine restart: unless-stopped environment: <<: *common-env POSTGRES_DB: ${POSTGRES_DB:-freetable} POSTGRES_USER: ${POSTGRES_USER:-freetable} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-changeme} PGDATA: /var/lib/postgresql/data/pgdata volumes: - freetable-db-data:/var/lib/postgresql/data # Optional: Mount SQL init scripts for schema setup # - ./initdb:/docker-entrypoint-initdb.d:ro networks: - freetable-network healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-freetable} -d ${POSTGRES_DB:-freetable}"] interval: 10s timeout: 5s retries: 5 start_period: 10s deploy: resources: limits: memory: 512M cpus: '0.5' reservations: memory: 128M cpus: '0.1' # ==================== Backend API ==================== backend: <<: *backend-base <<: *healthcheck-backend environment: <<: *common-env # Database DATABASE_URL: postgresql://${POSTGRES_USER:-freetable}:${POSTGRES_PASSWORD:-changeme}@db:5432/${POSTGRES_DB:-freetable} # Auth SECRET_KEY: ${SECRET_KEY:-your-secret-key-change-in-production} ALGORITHM: ${ALGORITHM:-HS256} ACCESS_TOKEN_EXPIRE_MINUTES: ${ACCESS_TOKEN_EXPIRE_MINUTES:-30} REFRESH_TOKEN_EXPIRE_DAYS: ${REFRESH_TOKEN_EXPIRE_DAYS:-7} # CORS CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost:3000} # File Uploads UPLOAD_DIR: /app/uploads MAX_UPLOAD_SIZE: ${MAX_UPLOAD_SIZE:-10485760} volumes: - freetable-uploads:/app/uploads expose: - "8000" deploy: resources: limits: memory: 768M cpus: '1.0' reservations: memory: 256M cpus: '0.25' labels: # Coolify Discovery coolify.version: "1.0" coolify.project.name: FreeTable coolify.service.name: backend coolify.service.type: api # Traefik labels for reverse proxy traefik.enable: "true" traefik.http.routers.freetable-backend.rule: "PathPrefix(`/api`)" traefik.http.routers.freetable-backend.entrypoints: websecure traefik.http.routers.freetable-backend.tls.certresolver: letsencrypt traefik.http.services.freetable-backend.loadbalancer.server.port: "8000" # ==================== Frontend (Nginx) ==================== frontend: image: nginx:alpine restart: unless-stopped environment: <<: *common-env BACKEND_HOST: backend BACKEND_PORT: "8000" PORT: "80" volumes: - ./frontend/dist:/usr/share/nginx/html:ro - ./nginx.conf:/etc/nginx/nginx.conf:ro networks: - freetable-network depends_on: backend: condition: service_healthy healthcheck: test: ["CMD", "wget", "-q", "--spider", "http://localhost/health"] interval: 30s timeout: 10s retries: 3 start_period: 10s expose: - "80" deploy: resources: limits: memory: 128M cpus: '0.5' reservations: memory: 32M cpus: '0.1' labels: # Coolify Discovery coolify.version: "1.0" coolify.project.name: FreeTable coolify.service.name: frontend coolify.service.type: web # Traefik labels for reverse proxy traefik.enable: "true" traefik.http.routers.freetable-web.rule: "Host(`${COOLIFY_DOMAIN}`)" traefik.http.routers.freetable-web.entrypoints: websecure traefik.http.routers.freetable-web.tls.certresolver: letsencrypt traefik.http.services.freetable-web.loadbalancer.server.port: "80" # ==================== Networks ==================== networks: freetable-network: driver: bridge name: freetable-network # ==================== Volumes ==================== volumes: freetable-db-data: name: freetable-db-data freetable-uploads: name: freetable-uploads