# Docker Compose for Coolify Deployment # Deploy all services in one run # # Usage in Coolify: # 1. Create new Docker Compose service # 2. Point to this file # 3. Set environment variables in Coolify UI # 4. Deploy services: # =========================================== # DATABASES # =========================================== postgres-backend: image: postgres:16-alpine container_name: placebo-postgres-backend restart: unless-stopped environment: POSTGRES_DB: placebo_backend_db POSTGRES_USER: placebo_user POSTGRES_PASSWORD: ${DATABASE_PASSWORD} volumes: - placebo-postgres-backend-data:/var/lib/postgresql/data expose: - "5432" healthcheck: test: ['CMD-SHELL', 'pg_isready -U placebo_user -d placebo_backend_db'] interval: 5s timeout: 5s retries: 10 start_period: 30s networks: - placebo-internal postgres-cms: image: postgres:16-alpine container_name: placebo-postgres-cms restart: unless-stopped environment: POSTGRES_DB: placebo_cms_db POSTGRES_USER: placebo_user POSTGRES_PASSWORD: ${DATABASE_PASSWORD} volumes: - placebo-postgres-cms-data:/var/lib/postgresql/data expose: - "5432" healthcheck: test: ['CMD-SHELL', 'pg_isready -U placebo_user -d placebo_cms_db'] interval: 5s timeout: 5s retries: 10 start_period: 30s networks: - placebo-internal # =========================================== # BACKEND (NestJS API) # =========================================== backend: build: context: ./backend dockerfile: Dockerfile container_name: placebo-backend restart: unless-stopped environment: NODE_ENV: production PORT: 3000 DATABASE_TYPE: postgres DATABASE_HOST: postgres-backend DATABASE_PORT: 5432 DATABASE_USERNAME: placebo_user DATABASE_PASSWORD: ${DATABASE_PASSWORD} DATABASE_NAME: placebo_backend_db DATABASE_SYNCHRONIZE: 'true' DATABASE_LOGGING: 'true' JWT_SECRET: ${JWT_SECRET} JWT_EXPIRATION: '86400' FRONTEND_URL: https://placebo.mk PWA_URL: https://app.placebo.mk STRAPI_URL: http://cms:1337 STRAPI_PUBLIC_URL: https://cms.placebo.mk VAPID_SUBJECT: ${VAPID_SUBJECT:-mailto:contact@placebo.mk} VAPID_PUBLIC_KEY: ${VAPID_PUBLIC_KEY} VAPID_PRIVATE_KEY: ${VAPID_PRIVATE_KEY} depends_on: postgres-backend: condition: service_healthy healthcheck: test: ['CMD', 'node', '-e', "require('http').get('http://127.0.0.1:3000/api/v1/health', (r) => {if(r.statusCode !== 200) process.exit(1)})"] interval: 30s timeout: 10s retries: 3 start_period: 40s networks: - placebo-internal - coolify expose: - "3000" labels: - "traefik.enable=true" # HTTP router (for Let's Encrypt challenge and redirect) - "traefik.http.routers.backend-http.rule=Host(`api.placebo.mk`)" - "traefik.http.routers.backend-http.entrypoints=http" - "traefik.http.routers.backend-http.middlewares=redirect-to-https" # HTTPS router - "traefik.http.routers.backend.rule=Host(`api.placebo.mk`)" - "traefik.http.routers.backend.entrypoints=https" - "traefik.http.routers.backend.tls=true" - "traefik.http.routers.backend.tls.certresolver=letsencrypt" - "traefik.http.routers.backend.service=backend" # Service - "traefik.http.services.backend.loadbalancer.server.port=3000" # Redirect middleware - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https" - "traefik.http.middlewares.redirect-to-https.redirectscheme.permanent=true" # =========================================== # CMS (Strapi) # =========================================== cms: build: context: ./cms/cms dockerfile: Dockerfile container_name: placebo-cms restart: unless-stopped environment: NODE_ENV: production HOST: 0.0.0.0 PORT: 1337 PUBLIC_URL: https://cms.placebo.mk BACKEND_WEBHOOK_URL: http://backend:3000 DATABASE_CLIENT: postgres DATABASE_HOST: postgres-cms DATABASE_PORT: '5432' DATABASE_NAME: placebo_cms_db DATABASE_USERNAME: placebo_user DATABASE_PASSWORD: ${DATABASE_PASSWORD} DATABASE_SSL: 'false' APP_KEYS: ${STRAPI_APP_KEYS} API_TOKEN_SALT: ${STRAPI_API_TOKEN_SALT} ADMIN_JWT_SECRET: ${STRAPI_ADMIN_JWT_SECRET} TRANSFER_TOKEN_SALT: ${STRAPI_TRANSFER_TOKEN_SALT} JWT_SECRET: ${STRAPI_JWT_SECRET} ENCRYPTION_KEY: ${STRAPI_ENCRYPTION_KEY} depends_on: postgres-cms: condition: service_healthy volumes: - placebo-cms-uploads:/app/public/uploads healthcheck: test: ['CMD', 'node', '-e', "require('http').get('http://127.0.0.1:1337/_health', (r) => {if(r.statusCode === 200 || r.statusCode === 204) process.exit(0); process.exit(1)})"] interval: 30s timeout: 10s retries: 3 start_period: 60s networks: - placebo-internal - coolify expose: - "1337" labels: - "traefik.enable=true" # HTTP router (for Let's Encrypt challenge and redirect) - "traefik.http.routers.cms-http.rule=Host(`cms.placebo.mk`)" - "traefik.http.routers.cms-http.entrypoints=http" - "traefik.http.routers.cms-http.middlewares=redirect-to-https" # HTTPS router - "traefik.http.routers.cms.rule=Host(`cms.placebo.mk`)" - "traefik.http.routers.cms.entrypoints=https" - "traefik.http.routers.cms.tls=true" - "traefik.http.routers.cms.tls.certresolver=letsencrypt" - "traefik.http.routers.cms.service=cms" # Service with timeouts - "traefik.http.services.cms.loadbalancer.server.port=1337" - "traefik.http.services.cms.loadbalancer.responseForwarding.flushInterval=100ms" # =========================================== # FRONTEND (React) # =========================================== frontend: build: context: ./frontend dockerfile: Dockerfile args: VITE_API_URL: https://api.placebo.mk/api/v1 VITE_CMS_URL: https://cms.placebo.mk container_name: placebo-frontend restart: unless-stopped depends_on: - backend healthcheck: test: ['CMD', 'wget', '--no-verbose', '--tries=1', '--spider', 'http://127.0.0.1:80/'] interval: 30s timeout: 10s retries: 3 networks: - placebo-internal - coolify expose: - "80" labels: - "traefik.enable=true" # HTTP router (for Let's Encrypt challenge and redirect) - "traefik.http.routers.frontend-http.rule=Host(`placebo.mk`) || Host(`www.placebo.mk`)" - "traefik.http.routers.frontend-http.entrypoints=http" - "traefik.http.routers.frontend-http.middlewares=redirect-to-https" # HTTPS router - "traefik.http.routers.frontend.rule=Host(`placebo.mk`) || Host(`www.placebo.mk`)" - "traefik.http.routers.frontend.entrypoints=https" - "traefik.http.routers.frontend.tls=true" - "traefik.http.routers.frontend.tls.certresolver=letsencrypt" - "traefik.http.routers.frontend.service=frontend" # Service - "traefik.http.services.frontend.loadbalancer.server.port=80" # =========================================== # PWA (Progressive Web App) # =========================================== pwa: build: context: ./pwa dockerfile: Dockerfile args: VITE_API_URL: https://api.placebo.mk/api/v1 VITE_CMS_URL: https://cms.placebo.mk container_name: placebo-pwa restart: unless-stopped depends_on: - backend healthcheck: test: ['CMD', 'wget', '--no-verbose', '--tries=1', '--spider', 'http://127.0.0.1:80/'] interval: 30s timeout: 10s retries: 3 networks: - placebo-internal - coolify expose: - "80" labels: - "traefik.enable=true" # HTTP router (for Let's Encrypt challenge and redirect) - "traefik.http.routers.pwa-http.rule=Host(`app.placebo.mk`)" - "traefik.http.routers.pwa-http.entrypoints=http" - "traefik.http.routers.pwa-http.middlewares=redirect-to-https" # HTTPS router - "traefik.http.routers.pwa.rule=Host(`app.placebo.mk`)" - "traefik.http.routers.pwa.entrypoints=https" - "traefik.http.routers.pwa.tls=true" - "traefik.http.routers.pwa.tls.certresolver=letsencrypt" - "traefik.http.routers.pwa.service=pwa" # Service - "traefik.http.services.pwa.loadbalancer.server.port=80" # =========================================== # VOLUMES (Managed by Coolify) # =========================================== volumes: placebo-postgres-backend-data: driver: local placebo-postgres-cms-data: driver: local placebo-cms-uploads: driver: local # =========================================== # NETWORKS # =========================================== networks: placebo-internal: driver: bridge coolify: external: true