168 lines
5.3 KiB
YAML
168 lines
5.3 KiB
YAML
version: '3.8'
|
|
|
|
services:
|
|
backend:
|
|
build: ./backend
|
|
ports:
|
|
- "127.0.0.1:8020:8000"
|
|
volumes:
|
|
- ./backend:/app
|
|
- backend_data:/app/data
|
|
environment:
|
|
- DATABASE_URL=${DATABASE_URL:-postgresql://elmeg:elmeg_password@db:5432/elmeg}
|
|
- SECRET_KEY=${SECRET_KEY:-demo-secret-change-in-production}
|
|
# Postal SMTP (primary)
|
|
- SMTP_HOST=${SMTP_HOST}
|
|
- SMTP_PORT=${SMTP_PORT:-25}
|
|
- SMTP_USERNAME=${SMTP_USERNAME}
|
|
- SMTP_PASSWORD=${SMTP_PASSWORD}
|
|
- SMTP_USE_TLS=${SMTP_USE_TLS:-true}
|
|
# AWS SES (fallback)
|
|
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
|
|
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
|
|
- AWS_SES_REGION=${AWS_SES_REGION}
|
|
# Common
|
|
- EMAIL_FROM=${EMAIL_FROM:-noreply@elmeg.xyz}
|
|
- FRONTEND_URL=${FRONTEND_URL:-https://elmeg.xyz}
|
|
command: sh start.sh
|
|
depends_on:
|
|
- db
|
|
restart: unless-stopped
|
|
healthcheck:
|
|
test: [ "CMD", "python", "-c", "import httpx; httpx.get('http://localhost:8000/docs').raise_for_status()" ]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
networks:
|
|
- elmeg
|
|
- traefik-public
|
|
- postal-internal
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.elmeg-backend.rule=(Host(`elmeg.runfoo.run`) || Host(`elmeg.xyz`)) && PathPrefix(`/api`)"
|
|
- "traefik.http.routers.elmeg-backend.entrypoints=websecure"
|
|
- "traefik.http.routers.elmeg-backend.tls.certresolver=letsencrypt"
|
|
- "traefik.http.routers.elmeg-backend.priority=100"
|
|
- "traefik.http.middlewares.elmeg-strip.stripprefix.prefixes=/api"
|
|
- "traefik.http.routers.elmeg-backend.middlewares=elmeg-strip"
|
|
- "traefik.http.routers.elmeg-backend.service=elmeg-backend-svc"
|
|
- "traefik.http.services.elmeg-backend-svc.loadbalancer.server.port=8000"
|
|
- "traefik.docker.network=traefik"
|
|
# Direct routes for docs (no strip)
|
|
- "traefik.http.routers.elmeg-backend-docs.rule=(Host(`elmeg.runfoo.run`) || Host(`elmeg.xyz`)) && PathPrefix(`/docs`, `/openapi.json`)"
|
|
- "traefik.http.routers.elmeg-backend-docs.entrypoints=websecure"
|
|
- "traefik.http.routers.elmeg-backend-docs.tls.certresolver=letsencrypt"
|
|
- "traefik.http.routers.elmeg-backend-docs.priority=100"
|
|
- "traefik.http.routers.elmeg-backend-docs.service=elmeg-backend-svc"
|
|
|
|
frontend:
|
|
build:
|
|
context: ./frontend
|
|
dockerfile: Dockerfile
|
|
ports:
|
|
- "127.0.0.1:3020:3000"
|
|
volumes:
|
|
- ./frontend:/app
|
|
- /app/node_modules
|
|
environment:
|
|
- NEXT_PUBLIC_API_URL=/api
|
|
- INTERNAL_API_URL=http://backend:8000
|
|
depends_on:
|
|
- backend
|
|
restart: unless-stopped
|
|
networks:
|
|
- elmeg
|
|
- traefik-public
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.elmeg-frontend.rule=(Host(`elmeg.runfoo.run`) || Host(`elmeg.xyz`)) && !PathPrefix(`/api`, `/docs`, `/openapi.json`)"
|
|
- "traefik.http.routers.elmeg-frontend.entrypoints=websecure"
|
|
- "traefik.http.routers.elmeg-frontend.tls.certresolver=letsencrypt"
|
|
- "traefik.http.routers.elmeg-frontend.priority=50"
|
|
- "traefik.http.services.elmeg-frontend.loadbalancer.server.port=3000"
|
|
- "traefik.docker.network=traefik"
|
|
|
|
db:
|
|
image: postgres:15-alpine
|
|
environment:
|
|
- POSTGRES_USER=elmeg
|
|
- POSTGRES_PASSWORD=elmeg_password
|
|
- POSTGRES_DB=elmeg
|
|
volumes:
|
|
- postgres_data:/var/lib/postgresql/data
|
|
restart: unless-stopped
|
|
healthcheck:
|
|
test: [ "CMD-SHELL", "pg_isready -U elmeg -d elmeg" ]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
networks:
|
|
- elmeg
|
|
|
|
db-backup:
|
|
image: prodrigestivill/postgres-backup-local:15-alpine
|
|
restart: unless-stopped
|
|
volumes:
|
|
- ./backups:/backups
|
|
- postgres_data:/var/lib/postgresql/data:ro
|
|
environment:
|
|
- POSTGRES_HOST=db
|
|
- POSTGRES_DB=elmeg
|
|
- POSTGRES_USER=elmeg
|
|
- POSTGRES_PASSWORD=elmeg_password
|
|
- SCHEDULE=@daily
|
|
- BACKUP_KEEP_DAYS=7
|
|
- BACKUP_KEEP_WEEKS=4
|
|
- BACKUP_KEEP_MONTHS=6
|
|
- HEALTHCHECK_PORT=80
|
|
depends_on:
|
|
- db
|
|
networks:
|
|
- elmeg
|
|
|
|
umami:
|
|
image: ghcr.io/umami-software/umami:postgresql-latest
|
|
restart: unless-stopped
|
|
environment:
|
|
- DATABASE_URL=postgresql://umami:umami_password@umami-db:5432/umami
|
|
- APP_SECRET=${UMAMI_SECRET:-highly-secret-key-change-this}
|
|
- TRACKER_SCRIPT_NAME=stats
|
|
depends_on:
|
|
- umami-db
|
|
networks:
|
|
- elmeg
|
|
- traefik-public
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.elmeg-umami.rule=Host(`stats.elmeg.xyz`) || Host(`stats.elmeg.runfoo.run`)"
|
|
- "traefik.http.routers.elmeg-umami.entrypoints=websecure"
|
|
- "traefik.http.routers.elmeg-umami.tls.certresolver=letsencrypt"
|
|
- "traefik.http.services.elmeg-umami.loadbalancer.server.port=3000"
|
|
- "traefik.docker.network=${TRAEFIK_NETWORK:-traefik}"
|
|
|
|
umami-db:
|
|
image: postgres:15-alpine
|
|
environment:
|
|
- POSTGRES_USER=umami
|
|
- POSTGRES_PASSWORD=umami_password
|
|
- POSTGRES_DB=umami
|
|
volumes:
|
|
- umami_data:/var/lib/postgresql/data
|
|
restart: unless-stopped
|
|
networks:
|
|
- elmeg
|
|
|
|
volumes:
|
|
postgres_data:
|
|
backend_data:
|
|
umami_data:
|
|
|
|
|
|
networks:
|
|
elmeg:
|
|
traefik-public:
|
|
name: ${TRAEFIK_NETWORK:-traefik}
|
|
external: true
|
|
postal-internal:
|
|
name: postal_postal-internal
|
|
external: true
|