ai-servers/docker-compose.yml

217 lines
6.1 KiB
YAML

services:
# ── Cache for SearXNG ──
valkey:
image: valkey/valkey:8-alpine
command: valkey-server --save 30 1 --loglevel warning
volumes:
- valkey-data:/data
restart: unless-stopped
healthcheck:
test: ["CMD", "valkey-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
# ── Private search engine ──
searxng:
image: searxng/searxng:latest
volumes:
- ./searxng:/etc/searxng:rw
environment:
- SEARXNG_SECRET_KEY=${SEARXNG_SECRET_KEY}
ports:
- "0.0.0.0:8080:8080"
depends_on:
valkey:
condition: service_healthy
restart: unless-stopped
# ── Vector database ──
chromadb:
image: chromadb/chroma:latest
volumes:
- chromadb-data:/chroma/chroma
ports:
- "0.0.0.0:8000:8000"
environment:
- IS_PERSISTENT=TRUE
- ANONYMIZED_TELEMETRY=FALSE
restart: unless-stopped
# # ── Database for LiteLLM (DEPRECATED — kept for rollback) ──
# litellm-db:
# image: postgres:16-alpine
# volumes:
# - litellm-db-data:/var/lib/postgresql/data
# environment:
# - POSTGRES_DB=litellm
# - POSTGRES_USER=litellm
# - POSTGRES_PASSWORD=${LITELLM_DB_PASSWORD}
# restart: unless-stopped
# healthcheck:
# test: ["CMD-SHELL", "pg_isready -U litellm"]
# interval: 10s
# timeout: 3s
# retries: 3
# # ── LLM API proxy (DEPRECATED — replaced by new-api) ──
# litellm:
# image: ghcr.io/berriai/litellm:main-latest
# command: ["--config", "/app/config.yaml", "--port", "4000"]
# volumes:
# - ./litellm/config.yaml:/app/config.yaml:ro
# ports:
# - "0.0.0.0:4000:4000"
# environment:
# - LITELLM_MASTER_KEY=${LITELLM_MASTER_KEY}
# - DATABASE_URL=postgresql://litellm:${LITELLM_DB_PASSWORD}@litellm-db:5432/litellm
# - OPENROUTER_API_KEY=${OPENROUTER_API_KEY}
# - SILICONFLOW_API_KEY=${SILICONFLOW_API_KEY}
# - DEEPINFRA_API_KEY=${DEEPINFRA_API_KEY}
# - GROQ_API_KEY=${GROQ_API_KEY}
# - CEREBRAS_API_KEY=${CEREBRAS_API_KEY}
# depends_on:
# litellm-db:
# condition: service_healthy
# restart: unless-stopped
# healthcheck:
# test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:4000/health/liveliness')"]
# interval: 15s
# timeout: 5s
# retries: 5
# start_period: 30s
# ── LLM API proxy (new-api) ──
new-api:
image: calciumion/new-api:latest
ports:
- "0.0.0.0:4000:3000"
volumes:
- new-api-data:/data
environment:
- SQL_DSN=
- TZ=UTC
- ENABLE_METRIC=true
- LANG=en_US.UTF-8
- INITIAL_ROOT_ACCESS_TOKEN=${NEW_API_ACCESS_TOKEN}
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://localhost:3000/"]
interval: 15s
timeout: 5s
retries: 5
start_period: 10s
# ── Chat UI ──
open-webui:
image: ghcr.io/open-webui/open-webui:main
volumes:
- open-webui-data:/app/backend/data
ports:
- "0.0.0.0:3000:8080"
environment:
- OLLAMA_BASE_URL=
- OPENAI_API_BASE_URL=http://new-api:3000/v1
- OPENAI_API_KEY=${OPENWEBUI_API_KEY}
- ENABLE_RAG_WEB_SEARCH=true
- RAG_WEB_SEARCH_ENGINE=searxng
- SEARXNG_QUERY_URL=http://searxng:8080/search?q=<query>&format=json
- CHROMA_HTTP_HOST=chromadb
- CHROMA_HTTP_PORT=8000
- WEBUI_AUTH=true
depends_on:
new-api:
condition: service_healthy
restart: unless-stopped
# ── Cloudflare Tunnel (public HTTPS) ──
cloudflared:
image: cloudflare/cloudflared:latest
command: tunnel run
environment:
- TUNNEL_TOKEN=${CLOUDFLARE_TUNNEL_TOKEN}
restart: unless-stopped
# ── Tailscale (private VPN access) ──
tailscale:
image: tailscale/tailscale:latest
hostname: ai-proxy
volumes:
- tailscale-state:/var/lib/tailscale
- /dev/net/tun:/dev/net/tun
cap_add:
- NET_ADMIN
- SYS_MODULE
environment:
- TS_AUTHKEY=${TS_AUTHKEY}
- TS_STATE_DIR=/var/lib/tailscale
- TS_USERSPACE=false
restart: unless-stopped
network_mode: host
# ═══════════════════════════════════════════════
# Monitoring stack
# ═══════════════════════════════════════════════
# ── Metrics store (Prometheus-compatible) ──
victoriametrics:
image: victoriametrics/victoria-metrics:latest
volumes:
- victoriametrics-data:/victoria-metrics-data
- ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
command:
- "-promscrape.config=/etc/prometheus/prometheus.yml"
- "-retentionPeriod=90d"
- "-storageDataPath=/victoria-metrics-data"
ports:
- "127.0.0.1:8428:8428"
restart: unless-stopped
# ── Dashboards ──
grafana:
image: grafana/grafana:latest
volumes:
- grafana-data:/var/lib/grafana
ports:
- "0.0.0.0:3001:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD}
- GF_USERS_ALLOW_SIGN_UP=false
depends_on:
- victoriametrics
restart: unless-stopped
# ── Host system metrics ──
node-exporter:
image: prom/node-exporter:latest
pid: host
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
command:
- "--path.procfs=/host/proc"
- "--path.sysfs=/host/sys"
- "--path.rootfs=/rootfs"
- "--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)"
restart: unless-stopped
# ── Valkey/Redis metrics ──
redis-exporter:
image: oliver006/redis_exporter:latest
environment:
- REDIS_ADDR=redis://valkey:6379
depends_on:
valkey:
condition: service_healthy
restart: unless-stopped
volumes:
valkey-data:
chromadb-data:
litellm-db-data:
new-api-data:
open-webui-data:
tailscale-state:
victoriametrics-data:
grafana-data: