services: # ========================================================== # Caddy — Reverse Proxy with Automatic HTTPS # Provisions Let's Encrypt TLS certificates automatically. # ========================================================== caddy: image: caddy:2-alpine container_name: taskapp-caddy restart: always ports: - "80:80" - "443:443" volumes: - ./caddy/Caddyfile:/etc/caddy/Caddyfile:ro - caddy_data:/data - caddy_config:/config - access_logs:/data environment: - DOMAIN_NAME=${DOMAIN_NAME:-localhost} depends_on: - frontend networks: - frontend-net # ========================================================== # Frontend — Nginx serving static files + reverse proxy to API # ========================================================== frontend: build: ./frontend container_name: taskapp-frontend restart: always expose: - "80" depends_on: - api networks: - frontend-net # ========================================================== # API — Node.js Express REST Backend # ========================================================== api: build: ./api container_name: taskapp-api restart: always expose: - "3000" environment: - PORT=3000 - POSTGRES_HOST=${POSTGRES_HOST:-postgres} - POSTGRES_PORT=${POSTGRES_PORT:-5432} - POSTGRES_DB=${POSTGRES_DB:-taskmanager} - POSTGRES_USER=${POSTGRES_USER:-taskuser} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-taskpass} - REDIS_HOST=${REDIS_HOST:-redis} - REDIS_PORT=${REDIS_PORT:-6379} depends_on: postgres: condition: service_healthy redis: condition: service_healthy networks: - frontend-net - backend-net # ========================================================== # PostgreSQL — Primary persistent database # ========================================================== postgres: image: postgres:16-alpine container_name: taskapp-postgres restart: always environment: - POSTGRES_DB=${POSTGRES_DB:-taskmanager} - POSTGRES_USER=${POSTGRES_USER:-taskuser} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-taskpass} volumes: - pgdata:/var/lib/postgresql/data - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql:ro healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-taskuser} -d ${POSTGRES_DB:-taskmanager}"] interval: 10s timeout: 5s retries: 5 start_period: 30s networks: - backend-net # ========================================================== # Redis — In-memory cache for fast API responses # ========================================================== redis: image: redis:7-alpine container_name: taskapp-redis restart: always command: redis-server --appendonly yes volumes: - redisdata:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5 networks: - backend-net # Named volumes for data persistence volumes: pgdata: name: taskapp-pgdata redisdata: name: taskapp-redisdata caddy_data: name: taskapp-caddy-data caddy_config: name: taskapp-caddy-config access_logs: name: taskapp-access-logs # Virtual networks for service isolation networks: frontend-net: name: taskapp-frontend-net backend-net: name: taskapp-backend-net