Docker Compose AI Platform: Self-Hosted Stack in One File
TL;DR — A Docker Compose AI platform deploys the entire self-hosted AI stack with one command:
docker compose up. The stack includes Ollama (LLM inference), PostgreSQL with pgvector (vector + SQL + ACLs), FalkorDB (knowledge graph), FastAPI (RAG API), Prometheus + Grafana (monitoring), and Nango (source connectors). GPU passthrough via NVIDIA Container Toolkit. Health checks ensure ordered startup. Named volumes for data persistence. Production-ready with restart policies, resource limits, and logging. Suitable for up to ~500 users on a single server. For larger deployments, migrate to Kubernetes. The minimum viable stack is Ollama + PostgreSQL + FastAPI — add services as needed. One file, one command, full self-hosted AI platform.
In 2026, self-hosted AI has gone mainstream. What used to require a GPU cluster and a PhD now runs on a single server with Docker Compose. One file defines the entire stack: LLM inference, vector database, knowledge graph, RAG API, monitoring, and source connectors.
Docker Compose solves three problems: reproducibility (same environment everywhere), orchestration (services start in order with health checks), and portability (move from laptop to server to cloud). This post provides the complete docker-compose.yml for a production-grade enterprise AI platform.
The Complete Docker Compose AI Stack
version: "3.9"
services:
# ============================================
# LLM Inference Layer
# ============================================
ollama:
image: ollama/ollama:latest
container_name: ollama
ports:
- "11434:11434"
volumes:
- ollama_data:/root/.ollama
restart: always
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
limits:
memory: 16G
healthcheck:
test: ["CMD-SHELL", "curl -sf http://localhost:11434/api/tags || exit 1"]
interval: 30s
timeout: 10s
retries: 3
# ============================================
# Data Layer: PostgreSQL + pgvector
# ============================================
postgres:
image: pgvector/pgvector:pg16
container_name: postgres
ports:
- "5432:5432"
environment:
POSTGRES_DB: aidb
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_INITDB_ARGS: "--encoding=UTF-8"
volumes:
- pg_data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
restart: always
deploy:
resources:
limits:
memory: 8G
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d aidb"]
interval: 10s
timeout: 5s
retries: 5
# ============================================
# Knowledge Graph: FalkorDB
# ============================================
falkordb:
image: falkordb/falkordb:latest
container_name: falkordb
ports:
- "6379:6379"
volumes:
- falkor_data:/data
restart: always
command: ["--save", "60", "1", "--loglevel", "warning"]
deploy:
resources:
limits:
memory: 4G
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 3
# ============================================
# RAG API: FastAPI
# ============================================
api:
build: .
container_name: rag-api
ports:
- "8000:8000"
environment:
DATABASE_URL: postgresql+asyncpg://postgres:${DB_PASSWORD}@postgres/aidb
FALKORDB_URL: redis://falkordb:6379
OLLAMA_URL: http://ollama:11434
EMBEDDING_MODEL: BAAI/bge-large-en-v1.5
RERANKER_MODEL: BAAI/bge-reranker-v2-m3
CACHE_THRESHOLD: "0.95"
CONFIDENCE_THRESHOLD: "0.1"
depends_on:
postgres:
condition: service_healthy
falkordb:
condition: service_healthy
ollama:
condition: service_healthy
restart: always
deploy:
resources:
limits:
memory: 4G
healthcheck:
test: ["CMD", "curl", "-sf", "http://localhost:8000/health"]
interval: 30s
timeout: 5s
retries: 3
# ============================================
# Source Connectors: Nango
# ============================================
nango:
image: nangohq/nango:latest
container_name: nango
ports:
- "3003:3003"
environment:
NANGO_ENCRYPTION_KEY: ${NANGO_ENCRYPTION_KEY}
SERVER_PORT: "3003"
volumes:
- nango_data:/var/lib/nango
restart: always
# ============================================
# Monitoring: Prometheus + Grafana
# ============================================
prometheus:
image: prom/prometheus:latest
container_name: prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus_data:/prometheus
restart: always
grafana:
image: grafana/grafana:latest
container_name: grafana
ports:
- "3000:3000"
environment:
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD}
volumes:
- grafana_data:/var/lib/grafana
depends_on:
- prometheus
restart: always
# ============================================
# Reverse Proxy: Nginx (production TLS)
# ============================================
nginx:
image: nginx:alpine
container_name: nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./certs:/etc/nginx/certs:ro
depends_on:
- api
restart: always
profiles: ["production"]
volumes:
ollama_data:
pg_data:
falkor_data:
nango_data:
prometheus_data:
grafana_data:
Service Architecture
TLS + Rate Limiting"] end subgraph App["Application Layer"] API["FastAPI
RAG Orchestration"] Nango["Nango
Source Connectors"] end subgraph AI["AI Layer"] Ollama["Ollama
LLM Inference
(GPU)"] end subgraph Data["Data Layer"] PG["PostgreSQL
+ pgvector
Vectors + SQL + ACLs"] Falkor["FalkorDB
Knowledge Graph"] end subgraph Ops["Operations Layer"] Prom["Prometheus
Metrics"] Grafana["Grafana
Dashboards"] end Nginx --> API API --> Ollama API --> PG API --> Falkor Nango --> PG API -.->|"metrics"| Prom Prom --> Grafana
Service Overview
| Service | Purpose | Port | Resource Limit | Health Check |
|---|---|---|---|---|
| Ollama | LLM inference (Llama 3, Mistral) | 11434 | 16GB RAM + GPU | /api/tags |
| PostgreSQL | Vectors, SQL, ACLs, audit | 5432 | 8GB RAM | pg_isready |
| FalkorDB | Knowledge graph | 6379 | 4GB RAM | redis-cli ping |
| FastAPI | RAG API orchestration | 8000 | 4GB RAM | /health |
| Nango | Source connectors | 3003 | 1GB RAM | — |
| Prometheus | Metrics collection | 9090 | 1GB RAM | — |
| Grafana | Dashboards | 3000 | 1GB RAM | — |
| Nginx | TLS + rate limiting | 80/443 | 512MB RAM | — |
Total resource footprint: ~35GB RAM + 1 GPU. Fits on a single server with 64GB RAM and 1 NVIDIA GPU.
Production Patterns
GPU Passthrough
# Requires NVIDIA Container Toolkit on host
# Install: distribution=$(. /etc/os-release; echo $ID$VERSION_ID)
# curl -s -L https://nvidia.github.io/libnvidia-container/gpgkey | sudo apt-key add -
# sudo apt-get install -y nvidia-container-toolkit
# sudo systemctl restart docker
ollama:
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1 # or device_ids: ["0", "1"] for specific GPUs
capabilities: [gpu]
Health Check Ordering
api:
depends_on:
postgres:
condition: service_healthy # Wait for PostgreSQL to be ready
falkordb:
condition: service_healthy # Wait for FalkorDB to be ready
ollama:
condition: service_healthy # Wait for Ollama to load model
Docker Compose Profiles
# Development profile (no Nginx, no TLS)
# Usage: docker compose up
# Nginx only starts with: docker compose --profile production up
nginx:
profiles: ["production"]
# Monitoring only starts with: docker compose --profile monitoring up
prometheus:
profiles: ["monitoring"]
grafana:
profiles: ["monitoring"]
Resource Limits
# Prevent any single service from consuming all resources
deploy:
resources:
limits:
memory: 16G
cpus: '4'
reservations:
memory: 8G
cpus: '2'
Dev vs Production Configuration
| Aspect | Development | Production |
|---|---|---|
| Restart policy | no |
always |
| Resource limits | None | Set per service |
| Health checks | Optional | Required |
| TLS | None (HTTP) | Nginx + Let's Encrypt |
| Logging | Console | JSON file with rotation |
| Profiles | Default only | production + monitoring |
| Secrets | .env file |
Docker secrets / vault |
| Networking | Default bridge | Custom network with aliases |
| Backups | Manual | Automated (cron + volume snapshots) |
Scaling Beyond Docker Compose
| Scale | Solution | When to Migrate |
|---|---|---|
| <500 users | Docker Compose (single server) | Start here |
| 500-2000 users | Docker Swarm (multi-node) | Need HA or more GPU |
| 2000+ users | Kubernetes | Need auto-scaling, rolling updates |
| Multi-region | Kubernetes + federation | Need geographic distribution |
Migration path: Docker Compose → Docker Swarm → Kubernetes. The docker-compose.yml converts to Docker Stack files (docker stack deploy) and Kubernetes manifests (using Kompose or Helm charts).
Docker Compose AI Platform Checklist
- [ ] Install Docker Engine + Docker Compose v2 on host
- [ ] Install NVIDIA driver + CUDA + NVIDIA Container Toolkit (for GPU)
- [ ] Create
.envfile withDB_PASSWORD,NANGO_ENCRYPTION_KEY,GRAFANA_PASSWORD - [ ] Create
init.sqlfor PostgreSQL (pgvector extension, tables, indexes, RLS) - [ ] Create
prometheus.ymlwith scrape targets for all services - [ ] Create
nginx.confwith TLS + rate limiting (production profile) - [ ] Build FastAPI Dockerfile (Python 3.12, asyncpg, redis-py, sentence-transformers)
- [ ] Pull LLM model:
docker exec ollama ollama pull llama3:70b - [ ] Configure GPU passthrough in Ollama service
- [ ] Set health checks for all services with appropriate intervals
- [ ] Configure
depends_onwithcondition: service_healthyfor ordered startup - [ ] Set resource limits (memory + CPU) per service
- [ ] Set
restart: alwaysfor production - [ ] Configure logging with
max-sizeandmax-filerotation - [ ] Use named volumes for all persistent data
- [ ] Test with
docker compose up(dev) anddocker compose --profile production up - [ ] Verify health checks pass:
docker compose ps - [ ] Set up hybrid retrieval in PostgreSQL
- [ ] Configure cross-encoder reranking in FastAPI
- [ ] Set up semantic answer caching (Redis or pgvector)
- [ ] Implement content hash deduplication in ingestion
- [ ] Configure document-level ACLs in PostgreSQL
- [ ] Set up Nango connectors for data sources
- [ ] Configure Prometheus alerts: latency p99, error rate, GPU utilization
- [ ] Create Grafana dashboards: query latency, cache hit rate, hallucination rate
- [ ] Set up automated backups: PostgreSQL PITR + FalkorDB RDB + volume snapshots
- [ ] Test disaster recovery: restore from backup
- [ ] Configure zero-trust security between services
- [ ] Monitor disk usage — LLM models and vectors consume significant space
- [ ] Consider self-hosted AI TCO for cost analysis
- [ ] Document the stack for AI company brain integration
FAQ
What is a Docker Compose AI platform?
A Docker Compose AI platform is a single docker-compose.yml file that defines and orchestrates all components of a self-hosted AI stack: LLM inference (Ollama or vLLM), vector database (PostgreSQL with pgvector), knowledge graph (FalkorDB), RAG API (FastAPI), monitoring (Prometheus + Grafana), and source connectors (Nango). Docker Compose handles networking, volume persistence, health checks, and service dependencies. One command (docker compose up) starts the entire platform. This simplifies deployment, ensures reproducibility, and makes the stack portable across environments.
How do you deploy an AI stack with Docker Compose?
Create a docker-compose.yml file defining each service (Ollama, PostgreSQL, FalkorDB, FastAPI, Prometheus), their ports, volumes, environment variables, and dependencies. Use health checks to ensure services start in order. Configure GPU passthrough with the NVIDIA Container Toolkit for LLM inference. Use named volumes for data persistence. Run 'docker compose up -d' to start all services. For production, add resource limits, restart policies, and logging configuration. The entire stack can be deployed on a single server or split across multiple machines using Docker Swarm or Kubernetes.
Can Docker Compose handle production AI workloads?
Docker Compose is suitable for small to medium production deployments (up to ~500 users). For larger deployments, migrate to Kubernetes. Docker Compose production considerations: use restart: always, set resource limits (memory, CPU), configure health checks, use named volumes for persistence, enable GPU passthrough for LLM inference, set up logging (ELK or Loki), and use Docker Compose profiles to separate dev and prod configurations. For high availability, use Docker Swarm (multi-node) or migrate to Kubernetes. Many teams run production AI on Docker Compose with a single powerful server.
How do you configure GPU passthrough in Docker Compose?
Install the NVIDIA Container Toolkit on the host, then specify GPU resources in docker-compose.yml under deploy.resources.reservations.devices. For a single GPU: 'driver: nvidia, count: 1, capabilities: [gpu]'. For specific GPUs: 'device_ids: [\"0\", \"1\"]'. Ollama and vLLM automatically detect and use available GPUs. Ensure the NVIDIA driver and CUDA are installed on the host. Test with 'docker run --rm --gpus all nvidia/cuda:12.0-base nvidia-smi' before deploying the full stack.
What services should a Docker Compose AI platform include?
Core services: Ollama or vLLM (LLM inference), PostgreSQL with pgvector (vector + SQL + ACLs), FalkorDB (knowledge graph), FastAPI (RAG API). Supporting services: Prometheus + Grafana (monitoring), Nango (source connectors), BGE-Reranker (cross-encoder reranking). Optional: OpenSearch (if you need better full-text search than PostgreSQL tsvector), Redis (semantic cache), Nginx (reverse proxy + TLS). The minimum viable stack is Ollama + PostgreSQL + FastAPI. Add services as your use case demands.
Want a self-hosted AI company brain that does all of this out of the box?
Book a demo →