services: # Nginx reverse proxy - Main application entry point enclava-nginx: image: nginx:alpine ports: - "80:80" # Main application access (nginx proxy) volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro depends_on: - enclava-backend - enclava-frontend networks: - enclava-net restart: unless-stopped # Database migration service - runs once to apply migrations enclava-migrate: build: context: ./backend dockerfile: Dockerfile environment: - DATABASE_URL=postgresql://enclava_user:enclava_pass@enclava-postgres:5432/enclava_db - JWT_SECRET=${JWT_SECRET:-your-jwt-secret-here} depends_on: - enclava-postgres command: ["/usr/local/bin/migrate.sh"] volumes: - ./backend:/app - ./.env:/app/.env networks: - enclava-net restart: "no" # Run once and exit # Main application backend enclava-backend: build: context: ./backend dockerfile: Dockerfile environment: - DATABASE_URL=postgresql://enclava_user:enclava_pass@enclava-postgres:5432/enclava_db - REDIS_URL=redis://enclava-redis:6379 - QDRANT_HOST=enclava-qdrant - JWT_SECRET=${JWT_SECRET:-your-jwt-secret-here} - PRIVATEMODE_API_KEY=${PRIVATEMODE_API_KEY:-} - ADMIN_EMAIL=${ADMIN_EMAIL} - ADMIN_PASSWORD=${ADMIN_PASSWORD} - LOG_LLM_PROMPTS=${LOG_LLM_PROMPTS:-false} - BASE_URL=${BASE_URL} # Agent & Tool Calling System - Web Search - BRAVE_SEARCH_API_KEY=${BRAVE_SEARCH_API_KEY:-} # Agent & Tool Calling System - MCP Servers (pass all MCP_* env vars) # Example: MCP_ORDER_API_URL, MCP_ORDER_API_KEY, MCP_WEATHER_URL, etc. depends_on: - enclava-migrate - enclava-postgres - enclava-redis - enclava-qdrant - privatemode-proxy # Removed external port mapping - access through nginx proxy volumes: - ./backend:/app - ./logs:/app/logs - ./plugins:/plugins # Docker socket for code execution sandbox # SECURITY NOTE: This allows the backend to spawn Docker containers # In production, consider using Docker-in-Docker or restricting permissions - /var/run/docker.sock:/var/run/docker.sock networks: - enclava-net restart: unless-stopped # Next.js frontend enclava-frontend: image: node:18-alpine working_dir: /app command: sh -c "npm ci --ignore-scripts && npm run dev" environment: # Required base URL (derives APP/API/WS URLs) - BASE_URL=${BASE_URL} - NEXT_PUBLIC_BASE_URL=${BASE_URL} # Internal API URL - INTERNAL_API_URL=http://enclava-backend:8000 depends_on: - enclava-backend ports: - "3002:3000" # Direct frontend access for development volumes: - ./frontend:/app - enclava-frontend-node-modules:/app/node_modules networks: - enclava-net restart: unless-stopped dns: - 8.8.8.8 - 1.1.1.1 # PostgreSQL database enclava-postgres: image: postgres:16 environment: - POSTGRES_DB=enclava_db - POSTGRES_USER=enclava_user - POSTGRES_PASSWORD=enclava_pass volumes: - enclava-postgres-data:/var/lib/postgresql/data - ./backend/migrations:/docker-entrypoint-initdb.d networks: - enclava-net restart: unless-stopped # Redis for caching and message queue enclava-redis: image: redis:7-alpine command: redis-server --appendonly yes volumes: - enclava-redis-data:/data networks: - enclava-net restart: unless-stopped # Qdrant vector database enclava-qdrant: image: qdrant/qdrant:latest environment: - QDRANT__SERVICE__HTTP_PORT=6333 - QDRANT__SERVICE__GRPC_PORT=6334 ports: - "56333:6333" # HTTP API and Web Interface - "56334:6334" # GRPC API (optional) volumes: - enclava-qdrant-data:/qdrant/storage networks: - enclava-net restart: unless-stopped # Privatemode.ai service (optional - for confidential models) privatemode-proxy: image: ghcr.io/edgelesssys/privatemode/privatemode-proxy:latest environment: - PRIVATEMODE_API_KEY=${PRIVATEMODE_API_KEY:-} - PRIVATEMODE_CACHE_MODE=${PRIVATEMODE_CACHE_MODE:-none} - PRIVATEMODE_CACHE_SALT=${PRIVATEMODE_CACHE_SALT:-} entrypoint: ["/bin/privatemode-proxy"] command: [ "--apiKey=${PRIVATEMODE_API_KEY}", "--port=8080" ] ports: - "58080:8080" networks: - enclava-net restart: unless-stopped volumes: enclava-postgres-data: enclava-redis-data: enclava-qdrant-data: enclava-frontend-node-modules: # enclava-ollama-data: networks: enclava-net: driver: bridge