Docker Compose Full AI Stack
One command to deploy Ollama, Open WebUI, and Nginx with SSL. The production-ready foundation for self-hosted AI infrastructure.
Running individual AI tools is simple. Running them together securely, with reverse proxy, SSL, and persistence, is where most people get stuck. This recipe gives you a single docker-compose.yml that deploys:
- Ollama — the local LLM engine
- Open WebUI — a ChatGPT-like web interface
- Nginx — reverse proxy with SSL termination
- Persistent volumes — models and data survive container restarts
One command: docker compose up -d. Production-ready architecture.
- Complete AI stack running in Docker
- HTTPS access via Nginx with Let's Encrypt
- Persistent model storage (no re-download on restart)
- Web UI accessible at
https://ai.yourdomain.com - Ollama API available internally on the Docker network
- Docker and Docker Compose installed
- A domain name pointing to your server
- Ports 80 and 443 open
- 20GB free disk space (models are large)
- Optional but recommended: a server with a GPU
Update the stack
docker compose pull
docker compose up -d
Backup models
tar -czf ollama-backup-$(date +%Y%m%d).tar.gz ollama-data/
View logs
docker compose logs -f ollama
docker compose logs -f open-webui
For NVIDIA GPUs, uncomment the deploy section in docker-compose.yml and ensure the NVIDIA Container Toolkit is installed:
# Install NVIDIA Container Toolkit
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
sudo apt update
sudo apt install -y nvidia-container-toolkit
sudo systemctl restart docker
"Bind for 0.0.0.0:80 failed"
Another service is using port 80. Check with:
sudo lsof -i :80
Stop the conflicting service or change the port mapping in docker-compose.yml.
Models not persisting
Ensure the volume mount is correct:
ls -la ollama-data/
You should see models/ directory. If empty, check Docker volume permissions.
SSL certificate errors
If using self-signed certificates for testing, add the -k flag to curl or accept the warning in your browser. For production, use Let's Encrypt.
Teams and individuals who want a production-ready, reproducible AI infrastructure. Docker Compose makes this stack portable between development laptops, home servers, and cloud VPS instances.
Steps
mkdir ~/ai-stack && cd ~/ai-stack
mkdir -p {nginx/conf.d,ollama-data,webui-data}
services:
ollama:
image: ollama/ollama:latest
container_name: ollama
volumes:
- ./ollama-data:/root/.ollama
ports:
- "11434:11434"
environment:
- OLLAMA_ORIGINS=*
restart: unless-stopped
# Uncomment for NVIDIA GPU support:
# deploy:
# resources:
# reservations:
# devices:
# - driver: nvidia
# count: 1
# capabilities: [gpu]
open-webui:
image: ghcr.io/open-webui/open-webui:main
container_name: open-webui
volumes:
- ./webui-data:/app/backend/data
ports:
- "3000:8080"
environment:
- OLLAMA_BASE_URL=http://ollama:11434
- WEBUI_AUTH=False
- WEBUI_NAME=AI Stack
depends_on:
- ollama
restart: unless-stopped
nginx:
image: nginx:alpine
container_name: nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d:ro
- ./nginx/ssl:/etc/nginx/ssl:ro
depends_on:
- open-webui
restart: unless-stopped
Create nginx/conf.d/default.conf:
server {
listen 80;
server_name ai.yourdomain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name ai.yourdomain.com;
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
location / {
proxy_pass http://open-webui:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
location /ollama/ {
proxy_pass http://ollama:11434/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
For Let's Encrypt (recommended):
# Install certbot
docker run -it --rm --name certbot \
-v "$(pwd)/nginx/ssl:/etc/letsencrypt" \
-v "$(pwd)/nginx/www:/var/www/certbot" \
certbot/certbot certonly \
--standalone \
-d ai.yourdomain.com \
--agree-tos \
--email your-email@example.com
Copy certificates:
sudo cp /etc/letsencrypt/live/ai.yourdomain.com/fullchain.pem nginx/ssl/
sudo cp /etc/letsencrypt/live/ai.yourdomain.com/privkey.pem nginx/ssl/
docker compose up -d
Verify:
docker compose ps
All services should show "Up".
docker exec -it ollama ollama pull qwen3.5:9b
Navigate to https://ai.yourdomain.com. You should see the Open WebUI login screen.
- Create an admin account
- Go to Settings → Models
- Verify qwen3.5:9b appears
- Start a new chat and test
Recipe verified Mon Jun 15 2026 00:00:00 GMT+0000 (Coordinated Universal Time). Commands are tested but your environment may differ.
Browse related services