services: # PostgreSQL with pgvector for AI/RAG workloads ai_postgres: image: ${AI_POSTGRES_IMAGE:-pgvector/pgvector:pg16} container_name: ${AI_COMPOSE_PROJECT_NAME}_postgres restart: unless-stopped environment: TZ: ${TIMEZONE:-Europe/Berlin} POSTGRES_USER: ${AI_DB_USER} POSTGRES_PASSWORD: ${AI_DB_PASSWORD} POSTGRES_DB: ${AI_DB_NAME} POSTGRES_HOST_AUTH_METHOD: scram-sha-256 POSTGRES_INITDB_ARGS: --auth-host=scram-sha-256 volumes: - ai_postgres_data:/var/lib/postgresql/data - ./postgres/init:/docker-entrypoint-initdb.d healthcheck: test: ["CMD-SHELL", "pg_isready -U ${AI_DB_USER}"] interval: 30s timeout: 10s retries: 3 start_period: 40s networks: - compose_network # Open WebUI - ChatGPT-like interface for AI models webui: image: ${AI_WEBUI_IMAGE:-ghcr.io/open-webui/open-webui:main} container_name: ${AI_COMPOSE_PROJECT_NAME}_webui restart: unless-stopped environment: TZ: ${TIMEZONE:-Europe/Berlin} # Database configuration DATABASE_URL: postgresql://${AI_DB_USER}:${AI_DB_PASSWORD}@ai_postgres:5432/${AI_DB_NAME} # OpenAI API configuration (pointing to LiteLLM proxy) OPENAI_API_BASE_URLS: http://litellm:4000 OPENAI_API_KEYS: ${AI_LITELLM_API_KEY} # Disable Ollama (we only use LiteLLM) ENABLE_OLLAMA_API: false OLLAMA_BASE_URLS: "" # WebUI configuration WEBUI_NAME: ${AI_WEBUI_NAME:-Pivoine AI} WEBUI_URL: https://${AI_TRAEFIK_HOST} WEBUI_SECRET_KEY: ${AI_WEBUI_SECRET_KEY} # Feature flags ENABLE_SIGNUP: ${AI_ENABLE_SIGNUP:-true} ENABLE_RAG_WEB_SEARCH: ${AI_ENABLE_RAG_WEB_SEARCH:-true} ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION: ${AI_ENABLE_RAG_SSL_VERIFY:-true} # RAG configuration RAG_EMBEDDING_ENGINE: ${AI_RAG_EMBEDDING_ENGINE:-openai} RAG_EMBEDDING_MODEL: ${AI_RAG_EMBEDDING_MODEL:-text-embedding-3-small} VECTOR_DB: ${AI_VECTOR_DB:-pgvector} # Email configuration (Mailpit SMTP relay) SMTP_HOST: net_mailpit SMTP_PORT: 1025 SMTP_FROM_EMAIL: ${EMAIL_FROM} SMTP_USE_TLS: false SMTP_USE_SSL: false volumes: - ai_webui_data:/app/backend/data - ./functions:/app/backend/data/functions:ro depends_on: - ai_postgres - litellm networks: - compose_network labels: - "traefik.enable=${AI_TRAEFIK_ENABLED}" # HTTP to HTTPS redirect - "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-redirect-web-secure.redirectscheme.scheme=https" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-web.middlewares=${AI_COMPOSE_PROJECT_NAME}-redirect-web-secure" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-web.rule=Host(`${AI_TRAEFIK_HOST}`)" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-web.entrypoints=web" # HTTPS router - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-web-secure.rule=Host(`${AI_TRAEFIK_HOST}`)" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-web-secure.tls.certresolver=resolver" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-web-secure.entrypoints=web-secure" - "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-web-secure-compress.compress=true" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-web-secure.middlewares=${AI_COMPOSE_PROJECT_NAME}-web-secure-compress,security-headers@file" # Service - "traefik.http.services.${AI_COMPOSE_PROJECT_NAME}-web-secure.loadbalancer.server.port=8080" - "traefik.docker.network=${NETWORK_NAME}" # Watchtower - "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}" # LiteLLM - Proxy to convert Anthropic API to OpenAI-compatible format litellm: image: ghcr.io/berriai/litellm:main-latest container_name: ${AI_COMPOSE_PROJECT_NAME}_litellm restart: unless-stopped environment: TZ: ${TIMEZONE:-Europe/Berlin} ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY} LITELLM_MASTER_KEY: ${AI_LITELLM_API_KEY} DATABASE_URL: postgresql://${AI_DB_USER}:${AI_DB_PASSWORD}@ai_postgres:5432/litellm GPU_VLLM_LLAMA_URL: ${GPU_VLLM_LLAMA_URL} GPU_VLLM_EMBED_URL: ${GPU_VLLM_EMBED_URL} # LITELLM_DROP_PARAMS: 'true' # DISABLED: Was breaking streaming NO_DOCS: "true" NO_REDOC: "true" # Performance optimizations LITELLM_LOG: "DEBUG" # Enable detailed logging for debugging streaming issues LITELLM_MODE: "PRODUCTION" # Production mode for better performance volumes: - ./litellm-config.yaml:/app/litellm-config.yaml:ro command: [ "--config", "/app/litellm-config.yaml", "--host", "0.0.0.0", "--port", "4000", ] depends_on: - ai_postgres networks: - compose_network healthcheck: disable: true labels: - "traefik.enable=${AI_TRAEFIK_ENABLED}" # HTTP to HTTPS redirect - "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-litellm-redirect-web-secure.redirectscheme.scheme=https" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-litellm-web.middlewares=${AI_COMPOSE_PROJECT_NAME}-litellm-redirect-web-secure" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-litellm-web.rule=Host(`${AI_LITELLM_TRAEFIK_HOST}`)" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-litellm-web.entrypoints=web" # HTTPS router - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-litellm-web-secure.rule=Host(`${AI_LITELLM_TRAEFIK_HOST}`)" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-litellm-web-secure.tls.certresolver=resolver" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-litellm-web-secure.entrypoints=web-secure" - "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-litellm-web-secure-compress.compress=true" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-litellm-web-secure.middlewares=${AI_COMPOSE_PROJECT_NAME}-litellm-web-secure-compress,security-headers@file" # Service - "traefik.http.services.${AI_COMPOSE_PROJECT_NAME}-litellm-web-secure.loadbalancer.server.port=4000" - "traefik.docker.network=${NETWORK_NAME}" # Watchtower - "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}" # Facefusion - AI face swapping and enhancement facefusion: build: context: . dockerfile: Dockerfile image: facefusion-patched:3.5.0-cpu container_name: ${AI_COMPOSE_PROJECT_NAME}_facefusion restart: unless-stopped tty: true command: ["python", "-u", "facefusion.py", "run"] environment: TZ: ${TIMEZONE:-Europe/Berlin} GRADIO_SERVER_NAME: "0.0.0.0" GRADIO_SERVER_PORT: "7860" volumes: - ai_facefusion_data:/workspace networks: - compose_network labels: - "traefik.enable=${AI_FACEFUSION_TRAEFIK_ENABLED}" # HTTP to HTTPS redirect - "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-facefusion-redirect-web-secure.redirectscheme.scheme=https" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-facefusion-web.middlewares=${AI_COMPOSE_PROJECT_NAME}-facefusion-redirect-web-secure" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-facefusion-web.rule=Host(`${AI_FACEFUSION_TRAEFIK_HOST}`)" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-facefusion-web.entrypoints=web" # HTTPS router with Authelia - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-facefusion-web-secure.rule=Host(`${AI_FACEFUSION_TRAEFIK_HOST}`)" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-facefusion-web-secure.tls.certresolver=resolver" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-facefusion-web-secure.entrypoints=web-secure" - "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-facefusion-web-secure-compress.compress=true" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-facefusion-web-secure.middlewares=${AI_COMPOSE_PROJECT_NAME}-facefusion-web-secure-compress,net-authelia,security-headers@file" # Service - "traefik.http.services.${AI_COMPOSE_PROJECT_NAME}-facefusion-web-secure.loadbalancer.server.port=7860" - "traefik.docker.network=${NETWORK_NAME}" # Watchtower - disabled for custom local image - "com.centurylinklabs.watchtower.enable=false" # ComfyUI - Node-based UI for Flux image generation (proxies to RunPod GPU) comfyui: image: nginx:alpine container_name: ${AI_COMPOSE_PROJECT_NAME}_comfyui restart: unless-stopped environment: TZ: ${TIMEZONE:-Europe/Berlin} GPU_SERVICE_HOST: ${GPU_TAILSCALE_HOST} GPU_SERVICE_PORT: ${COMFYUI_BACKEND_PORT:-8188} volumes: - ./nginx.conf.template:/etc/nginx/nginx.conf.template:ro command: /bin/sh -c "envsubst '$${GPU_SERVICE_HOST},$${GPU_SERVICE_PORT}' < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf && exec nginx -g 'daemon off;'" networks: - compose_network labels: - "traefik.enable=${AI_COMFYUI_TRAEFIK_ENABLED:-true}" # HTTP to HTTPS redirect - "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-comfyui-redirect-web-secure.redirectscheme.scheme=https" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-comfyui-web.middlewares=${AI_COMPOSE_PROJECT_NAME}-comfyui-redirect-web-secure" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-comfyui-web.rule=Host(`${AI_COMFYUI_TRAEFIK_HOST:-comfy.ai.pivoine.art}`)" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-comfyui-web.entrypoints=web" # HTTPS router with Authelia SSO - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-comfyui-web-secure.rule=Host(`${AI_COMFYUI_TRAEFIK_HOST:-comfy.ai.pivoine.art}`)" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-comfyui-web-secure.tls.certresolver=resolver" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-comfyui-web-secure.entrypoints=web-secure" - "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-comfyui-web-secure-compress.compress=true" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-comfyui-web-secure.middlewares=${AI_COMPOSE_PROJECT_NAME}-comfyui-web-secure-compress,net-authelia,security-headers@file" # Service - "traefik.http.services.${AI_COMPOSE_PROJECT_NAME}-comfyui-web-secure.loadbalancer.server.port=80" - "traefik.docker.network=${NETWORK_NAME}" # Watchtower - "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}" audiocraft: image: nginx:alpine container_name: ${AI_COMPOSE_PROJECT_NAME}_audiocraft restart: unless-stopped environment: TZ: ${TIMEZONE:-Europe/Berlin} GPU_SERVICE_HOST: ${GPU_TAILSCALE_HOST} GPU_SERVICE_PORT: ${AUDIOCRAFT_BACKEND_PORT:-7860} volumes: - ./nginx.conf.template:/etc/nginx/nginx.conf.template:ro command: /bin/sh -c "envsubst '$${GPU_SERVICE_HOST},$${GPU_SERVICE_PORT}' < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf && exec nginx -g 'daemon off;'" networks: - compose_network labels: - "traefik.enable=${AI_AUDIOCRAFT_TRAEFIK_ENABLED:-true}" # HTTP to HTTPS redirect - "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-audiocraft-redirect-web-secure.redirectscheme.scheme=https" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-audiocraft-web.middlewares=${AI_COMPOSE_PROJECT_NAME}-audiocraft-redirect-web-secure" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-audiocraft-web.rule=Host(`${AI_AUDIOCRAFT_TRAEFIK_HOST:-audiocraft.ai.pivoine.art}`)" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-audiocraft-web.entrypoints=web" # HTTPS router with Authelia SSO - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-audiocraft-web-secure.rule=Host(`${AI_AUDIOCRAFT_TRAEFIK_HOST:-audiocraft.ai.pivoine.art}`)" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-audiocraft-web-secure.tls.certresolver=resolver" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-audiocraft-web-secure.entrypoints=web-secure" - "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-audiocraft-web-secure-compress.compress=true" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-audiocraft-web-secure.middlewares=${AI_COMPOSE_PROJECT_NAME}-audiocraft-web-secure-compress,net-authelia,security-headers@file" # Service - "traefik.http.services.${AI_COMPOSE_PROJECT_NAME}-audiocraft-web-secure.loadbalancer.server.port=80" - "traefik.docker.network=${NETWORK_NAME}" # Watchtower - "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}" # Supervisor UI - Modern web interface for RunPod process management supervisor: image: dev.pivoine.art/valknar/supervisor-ui:latest container_name: ${AI_COMPOSE_PROJECT_NAME}_supervisor_ui restart: unless-stopped environment: TZ: ${TIMEZONE:-Europe/Berlin} NODE_ENV: production # Connect to RunPod Supervisor via Tailscale SUPERVISOR_HOST: ${GPU_TAILSCALE_HOST} SUPERVISOR_PORT: ${SUPERVISOR_BACKEND_PORT:-9001} # No auth needed - Supervisor has auth disabled (protected by Authelia) networks: - compose_network labels: - "traefik.enable=${AI_SUPERVISOR_TRAEFIK_ENABLED:-true}" # HTTP to HTTPS redirect - "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-supervisor-redirect-web-secure.redirectscheme.scheme=https" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-supervisor-web.middlewares=${AI_COMPOSE_PROJECT_NAME}-supervisor-redirect-web-secure" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-supervisor-web.rule=Host(`${AI_SUPERVISOR_TRAEFIK_HOST:-supervisor.ai.pivoine.art}`)" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-supervisor-web.entrypoints=web" # HTTPS router with Authelia SSO - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-supervisor-web-secure.rule=Host(`${AI_SUPERVISOR_TRAEFIK_HOST:-supervisor.ai.pivoine.art}`)" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-supervisor-web-secure.tls.certresolver=resolver" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-supervisor-web-secure.entrypoints=web-secure" - "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-supervisor-web-secure-compress.compress=true" - "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-supervisor-web-secure.middlewares=${AI_COMPOSE_PROJECT_NAME}-supervisor-web-secure-compress,net-authelia,security-headers@file" # Service (port 3000 for Next.js app) - "traefik.http.services.${AI_COMPOSE_PROJECT_NAME}-supervisor-web-secure.loadbalancer.server.port=3000" - "traefik.docker.network=${NETWORK_NAME}" # Watchtower - "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}" volumes: ai_postgres_data: name: ${AI_COMPOSE_PROJECT_NAME}_postgres_data ai_webui_data: name: ${AI_COMPOSE_PROJECT_NAME}_webui_data ai_facefusion_data: name: ${AI_COMPOSE_PROJECT_NAME}_facefusion_data