version: "3.9" services: # ─── PostgreSQL ────────────────────────────────────────────────────────── postgres: image: postgres:16-alpine container_name: ai_gateway_postgres restart: unless-stopped environment: POSTGRES_USER: litellm POSTGRES_PASSWORD: litellm POSTGRES_DB: litellm volumes: - postgres_data:/var/lib/postgresql/data networks: - gateway_net healthcheck: test: ["CMD-SHELL", "pg_isready -U litellm"] interval: 10s timeout: 5s retries: 5 # ─── LiteLLM Proxy Gateway ─────────────────────────────────────────────── litellm: image: ghcr.io/berriai/litellm:main-v1.81.14-stable container_name: ai_gateway_litellm restart: unless-stopped volumes: - ./litellm/config.yaml:/app/config.yaml:ro - litellm_data:/app/data environment: - STORE_MODEL_IN_DB=True - LITELLM_MASTER_KEY=${LITELLM_MASTER_KEY:-sk-gateway-master-key} - LITELLM_SALT_KEY=${LITELLM_SALT_KEY:-} - DATABASE_URL=postgresql://litellm:litellm@postgres:5432/litellm - PORT=4000 command: > --config /app/config.yaml --port 4000 --num_workers 2 depends_on: postgres: condition: service_healthy healthcheck: test: ["CMD-SHELL", "python3 -c \"import urllib.request; urllib.request.urlopen('http://localhost:4000/health/liveliness')\" || exit 1"] interval: 30s timeout: 10s retries: 5 start_period: 60s networks: - gateway_net # ─── Backend API ───────────────────────────────────────────────────────── backend: build: context: ./backend dockerfile: Dockerfile container_name: ai_gateway_backend restart: unless-stopped environment: - NODE_ENV=production - PORT=3001 - LITELLM_BASE_URL=http://litellm:4000 - LITELLM_MASTER_KEY=${LITELLM_MASTER_KEY:-sk-gateway-master-key} - DB_PATH=/app/data/gateway.db - JWT_SECRET=${JWT_SECRET:-super-secret-jwt-key-change-in-production} - GATEWAY_PUBLIC_URL=${GATEWAY_PUBLIC_URL:-http://localhost} - LOG_LEVEL=${LOG_LEVEL:-http} volumes: - backend_data:/app/data depends_on: litellm: condition: service_healthy networks: - gateway_net healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3001/api/health"] interval: 20s timeout: 5s retries: 3 start_period: 10s # ─── Frontend ───────────────────────────────────────────────────────────── frontend: build: context: ./frontend dockerfile: Dockerfile args: - VITE_API_BASE=/api - VITE_APP_NAME=AI Gateway Hub container_name: ai_gateway_frontend restart: unless-stopped networks: - gateway_net depends_on: - backend # ─── Nginx Reverse Proxy ────────────────────────────────────────────────── nginx: image: nginx:1.25-alpine container_name: ai_gateway_nginx restart: unless-stopped ports: - "${HTTP_PORT:-80}:80" volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro - nginx_logs:/var/log/nginx depends_on: backend: condition: service_healthy frontend: condition: service_started networks: - gateway_net volumes: postgres_data: litellm_data: backend_data: nginx_logs: networks: gateway_net: driver: bridge