placebo.mk/docker-compose.coolify.yml
echo 0ef26ba2f1 fix: add HTTP to HTTPS redirect and fix CMS Dockerfile
- Add HTTP router and redirect middleware for Let's Encrypt challenges
- Fix CMS Dockerfile to copy config from source (not dist)
- Add favicon.png to CMS container
- Enable automatic HTTPS redirect for all services
2026-02-24 17:52:51 +01:00

269 lines
8.4 KiB
YAML

# 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
healthcheck:
test: ['CMD-SHELL', 'pg_isready']
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
healthcheck:
test: ['CMD-SHELL', 'pg_isready']
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: 'false'
DATABASE_LOGGING: 'false'
JWT_SECRET: ${JWT_SECRET}
JWT_EXPIRATION: '86400'
CORS_ORIGIN: https://placebo.mk,https://www.placebo.mk,https://app.placebo.mk
STRAPI_URL: http://cms:1337
STRAPI_API_TOKEN: ${STRAPI_API_TOKEN}
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"
# 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
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"
# Service
- "traefik.http.services.cms.loadbalancer.server.port=1337"
# ===========================================
# 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"
# 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"
# 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