This guide deploys Ollama as a Docker container with a Tailscale sidecar — giving you a self-hosted AI model runtime accessible from anywhere on your Tailscale network. No API costs, no subscriptions, no data leaving your network. The setup builds on the standard Docker home lab environment (Ubuntu VM on Proxmox with Portainer, Watchtower, and Tailscale) — if you’ve followed along with those videos, you already have everything you need.
Model data and config will live under:
Check the container started correctly:
Ollama takes a moment to initialise on first start. Look for a line confirming it’s listening on port 11434.
Or pull from outside the container using the Tailscale URL once it’s registered:
You should get: Ollama is running. Test a generation request:
🎥 Watch the Video Tutorial
💡Why Ollama in Docker Instead of a VM?
The previous Ollama guide ran Ollama directly on a dedicated Ubuntu VM. Running it as a Docker container on your existing Docker host is a lighter-weight alternative — no separate VM overhead, managed alongside your other containers with Portainer and Watchtower, and accessible over Tailscale using the same sidecar pattern as the rest of your stack. It’s also easier to connect to other Docker services. Hermes Agent and Open WebUI running on the same Docker host can reach Ollama over the internal Docker network rather than going via Tailscale — faster and simpler.ℹ️Note: Hardware used: Dell Latitude 5411 — Ubuntu VM on Proxmox with 4 CPU cores, 12GB RAM, 512GB NVMe. No GPU. All inference runs on CPU. GitHub: compose.yml
🛠 What You’ll Need
- The Docker home lab environment from the Docker Home Lab Setup guide — Portainer, Watchtower, and Tailscale already configured
- Ollama Docker image — pulled automatically by Compose
- A Tailscale auth key for the Ollama sidecar
- Enough disk space for your chosen models — plan for 3–27 GB per model
📋Step-by-Step Setup
1. Folder structure
Following the standard convention, create the stack folder:mkdir -p /media/docker/scripts/ollama cd /media/docker/scripts/ollama
/media/docker/configs/ollama/— Ollama config and model storage/media/docker/configs/tailscale/ollama/— Tailscale state for the sidecar
2. Environment variables
Add the Ollama-specific variables to your.env file alongside the existing base variables. The Tailscale auth key goes in .env.secrets as usual:
# .env additions for Ollama OLLAMA_HOST=0.0.0.0:11434 OLLAMA_KEEP_ALIVE=5m OLLAMA_NUM_PARALLEL=1 OLLAMA_NUM_GPU=0 OLLAMA_MAX_LOADED_MODELS=1 OLLAMA_CONTEXT_LENGTH=8192
3. Environment variable reference
Each variable controls how Ollama behaves on a CPU-only home lab system:OLLAMA_HOST=0.0.0.0:11434— listens on all interfaces so other services (Hermes, Open WebUI, n8n) can connect to itOLLAMA_KEEP_ALIVE=5m— keeps the loaded model in memory for 5 minutes after the last request, avoiding a slow reload on the next queryOLLAMA_NUM_PARALLEL=1— only run one inference at a time on CPU-only systems; parallel requests on CPU will saturate your cores and slow everything downOLLAMA_NUM_GPU=0— CPU-only mode. Change to1if you have a compatible NVIDIA GPUOLLAMA_MAX_LOADED_MODELS=1— cap the number of models held in memory. On a 12GB RAM VM, loading more than one or two models at once causes memory pressureOLLAMA_CONTEXT_LENGTH=8192— maximum token context window per conversation. Lower this to reduce RAM usage; raise it if you have headroom and need longer conversations
4. compose.yml
services:
# =====================
# Ollama
# =====================
ollama:
image: ollama/ollama:latest
container_name: ollama
restart: unless-stopped
labels:
- "com.centurylinklabs.watchtower.enable=true"
environment:
- OLLAMA_HOST=0.0.0.0
- OLLAMA_KEEP_ALIVE=${OLLAMA_KEEP_ALIVE:-5m}
- OLLAMA_NUM_PARALLEL=${OLLAMA_NUM_PARALLEL:-1}
- OLLAMA_MAX_LOADED_MODELS=${OLLAMA_MAX_LOADED_MODELS:-1}
- OLLAMA_CONTEXT_LENGTH=${OLLAMA_CONTEXT_LENGTH:-8192}
volumes:
- ${CONFIG}/ollama:/root/.ollama
network_mode: service:ts-ollama
depends_on:
- ts-ollama
# Uncomment below if this host has an NVIDIA GPU passed through to Docker
# deploy:
# resources:
# reservations:
# devices:
# - driver: nvidia
# count: all
# capabilities: [gpu]
# =====================
# Ollama Tailscale Sidecar
# =====================
ts-ollama:
image: tailscale/tailscale:latest
container_name: ts-ollama
hostname: ollama
restart: unless-stopped
labels:
- "com.centurylinklabs.watchtower.enable=true"
cap_add:
- NET_ADMIN
- NET_RAW
volumes:
- ${CONFIG}/tailscale/ollama:/var/lib/tailscale
- /dev/net/tun:/dev/net/tun
environment:
- TS_STATE_DIR=/var/lib/tailscale
- TS_AUTHKEY=${TS_AUTHKEY}
- TS_HOSTNAME=ollama
- TS_ACCEPT_DNS=true
- TS_USERSPACE=false
ports:
- "11434:11434"
networks:
ollama_net:
ipv4_address: 172.20.15.10
networks:
ollama_net:
driver: bridge
ipam:
config:
- subnet: 172.20.15.0/24
gateway: 172.20.15.1
5. Bash aliases for quick Docker commands
Add these aliases to your~/.bashrc to save typing the full Compose command every time:
# Add to ~/.bashrc alias docker-up='docker compose --env-file /media/docker/scripts/.env --env-file /media/docker/secrets/.env.secrets up -d' alias docker-down='docker compose --env-file /media/docker/scripts/.env --env-file /media/docker/secrets/.env.secrets down' alias docker-logs='docker compose --env-file /media/docker/scripts/.env --env-file /media/docker/secrets/.env.secrets logs -f'
source ~/.bashrc
💡Tip: With these aliases set, bringing up the Ollama stack from its folder is just
docker-up. No more typing out the full env-file paths every time.6. Deploy the stack
From the/media/docker/scripts/ollama folder:
docker-up
docker compose ps docker logs ollama
7. Approve the Tailscale device
Open your Tailscale admin console — ollama should appear as a new device. Approve it if auto-approve isn’t enabled and disable key expiry so it stays connected permanently.8. Pull your first model
Exec into the Ollama container to pull a model:docker exec -it ollama ollama pull llama2
curl http://ollama.your-tailnet.ts.net:11434/api/pull -d '{\"name\": \"llama2\"}'
⚠️Warning: Models are large files. Plan your storage before pulling. A Llama 2 pull is ~3.8 GB, Mistral is ~4.7 GB. The first pull takes time depending on your internet speed — be patient and don’t interrupt it.
9. Recommended models for CPU-only home labs
These four strike the best balance between capability and resource usage on a CPU-only 12GB VM:- llama2 (3.8 GB) — excellent all-round model, balanced performance across most tasks
- mistral (4.7 GB) — fast and efficient with strong quality, good for general use
- neural-chat (4.1 GB) — optimised for conversational use cases
- qwen (2.2 GB) — smallest option, fastest to load, good starting point for low-RAM setups
10. Test the API endpoint
Confirm Ollama is reachable and responding via the Tailscale URL:curl http://ollama.your-tailnet.ts.net:11434
curl http://ollama.your-tailnet.ts.net:11434/api/generate \\
-d '{\"model\": \"llama2\", \"prompt\": \"Explain Docker in one sentence.\", \"stream\": false}'
11. Model management
Useful commands for managing models once you have several pulled:# List installed models docker exec ollama ollama list# Pull a new model docker exec ollama ollama pull mistral # Delete a model to free space docker exec ollama ollama rm llama2 # Monitor resource usage docker stats ollama
12. Connect Ollama to other services
With Ollama running on Tailscale, other services in your home lab can connect to it using the Tailscale hostname:- Hermes Agent — point the model URL to
http://ollama.your-tailnet.ts.net:11434in Hermes config - Open WebUI — set
OLLAMA_BASE_URL=http://ollama.your-tailnet.ts.net:11434in the Open WebUI container environment - n8n — use the HTTP Request node pointing to
http://ollama.your-tailnet.ts.net:11434/api/generate - Claude Code — configure the Ollama API endpoint for local model use
⚠️Warning: Monitor your Docker resource usage with
docker stats. Ollama on CPU can consume all available cores during inference — if it’s competing with other containers on the same host, consider the dedicated VM approach from the earlier Ollama guide instead.