Files
Containr/docker-compose.yml
T
2026-02-23 16:43:39 +01:00

175 lines
6.1 KiB
YAML

services:
# Traefik Reverse Proxy
traefik:
image: traefik:v3.2
container_name: containr-traefik
command:
- "--api.dashboard=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.myresolver.acme.httpchallenge=true"
- "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.myresolver.acme.email=${ACME_EMAIL:-admin@localhost}"
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
- "--log.level=${LOG_LEVEL:-INFO}"
- "--accesslog=true"
- "--metrics.prometheus=true"
- "--ping=true"
ports:
- "80:80"
- "443:443"
- "8080:8080" # Traefik dashboard
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./data/letsencrypt:/letsencrypt
networks:
- containr-network
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.rule=Host(`traefik.${DOMAIN:-localhost}`)"
- "traefik.http.routers.traefik.entrypoints=websecure"
- "traefik.http.routers.traefik.tls.certresolver=myresolver"
- "traefik.http.routers.traefik.service=api@internal"
- "traefik.http.routers.traefik.middlewares=traefik-auth"
- "traefik.http.middlewares.traefik-auth.basicauth.users=${TRAEFIK_AUTH}"
restart: unless-stopped
healthcheck:
test: ["CMD", "traefik", "ping"]
interval: 30s
timeout: 10s
retries: 3
# PostgreSQL Database
postgres:
image: postgres:15-alpine
container_name: containr-postgres
environment:
POSTGRES_DB: ${POSTGRES_DB:-containr}
POSTGRES_USER: ${POSTGRES_USER:-containr_user}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-dev_password_123}
volumes:
- postgres_data:/var/lib/postgresql/data
- ./migrations:/docker-entrypoint-initdb.d
networks:
- containr-network
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-containr_user} -d ${POSTGRES_DB:-containr}"]
interval: 30s
timeout: 10s
retries: 3
# Redis Cache
redis:
image: redis:7-alpine
container_name: containr-redis
command: redis-server --requirepass ${REDIS_PASSWORD:-dev_redis_123}
volumes:
- redis_data:/data
networks:
- containr-network
restart: unless-stopped
healthcheck:
test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
interval: 30s
timeout: 10s
retries: 3
# Backend API
backend:
build:
context: .
dockerfile: Dockerfile.backend
container_name: containr-backend
ports:
- "8081:8080" # Temporary direct access
environment:
- DATABASE_URL=postgres://${POSTGRES_USER:-containr_user}:${POSTGRES_PASSWORD:-dev_password_123}@postgres:5432/${POSTGRES_DB:-containr}?sslmode=disable
- REDIS_URL=redis://:${REDIS_PASSWORD:-dev_redis_123}@redis:6379
- PORT=8080
- ENVIRONMENT=${ENVIRONMENT:-production}
- JWT_SECRET=${JWT_SECRET:-dev_jwt_secret_key_change_in_production}
- CORS_ALLOWED_ORIGINS=${CORS_ALLOWED_ORIGINS:-http://localhost,http://localhost:3000}
volumes:
# /var/run/docker.sock:/var/run/docker.sock:ro # Commented out to prevent permission issues
# Development volumes (only mounted in dev mode)
- ${DEV_MODE:-./internal}:/app/internal
networks:
- containr-network
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
restart: unless-stopped
labels:
- "traefik.enable=true"
- "traefik.http.routers.backend.rule=Host(`api.${DOMAIN:-localhost}`)"
- "traefik.http.routers.backend.entrypoints=websecure"
- "traefik.http.routers.backend.tls.certresolver=myresolver"
- "traefik.http.services.backend.loadbalancer.server.port=8080"
- "traefik.http.routers.backend.middlewares=cors-headers"
- "traefik.http.middlewares.cors-headers.headers.accesscontrolallowmethods=GET,POST,PUT,DELETE,OPTIONS"
- "traefik.http.middlewares.cors-headers.headers.accesscontrolalloworiginlist=${CORS_ALLOWED_ORIGINS:-http://localhost,http://localhost:3000}"
- "traefik.http.middlewares.cors-headers.headers.accesscontrolallowcredentials=true"
- "traefik.http.middlewares.cors-headers.headers.accesscontrolallowheaders=Content-Type,Authorization"
# Frontend
frontend:
build:
context: .
dockerfile: Dockerfile.frontend
container_name: containr-frontend
ports:
- "3000:80" # Temporary direct access
environment:
- VITE_API_URL=${VITE_API_URL:-http://api.localhost}
- VITE_ENVIRONMENT=${ENVIRONMENT:-production}
volumes:
# Development volumes (only mounted in dev mode)
- ${DEV_MODE:-./src}:/app/src
- ${DEV_MODE:-./public}:/app/public
networks:
- containr-network
depends_on:
- backend
restart: unless-stopped
labels:
- "traefik.enable=true"
- "traefik.http.routers.frontend.rule=Host(`${DOMAIN:-localhost}`)"
- "traefik.http.routers.frontend.entrypoints=websecure"
- "traefik.http.routers.frontend.tls.certresolver=myresolver"
- "traefik.http.services.frontend.loadbalancer.server.port=80"
- "traefik.http.routers.frontend-redirect.rule=Host(`${DOMAIN:-localhost}`)"
- "traefik.http.routers.frontend-redirect.entrypoints=web"
- "traefik.http.routers.frontend-redirect.middlewares=redirect-to-https"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
# Cloudflared Tunnel (optional)
cloudflared:
image: cloudflare/cloudflared:latest
container_name: containr-cloudflared
command: tunnel --no-autoupdate run --token ${CLOUDFLARED_TOKEN}
networks:
- containr-network
restart: unless-stopped
depends_on:
- traefik
profiles:
- cloudflared
volumes:
postgres_data:
driver: local
redis_data:
driver: local
networks:
containr-network:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16