AIAI Coding AgentsLLMDockerSelf-Hosting
Open WebUI + Ollama with Docker Compose: Full 2026 Setup (Linux, Windows, Mac)
Before you start
- 18 min read
Boxes marked Run in terminal are what you type; plain text explains why. Check what you need first

What you get in one minute#
Open WebUI is a self-hosted chat page for AI models, and Ollama is the program that runs the models - together they give you a private ChatGPT-style assistant on your own computer.
Your chats, documents and users stay on your machine. You can upload files and ask questions about them, search the web, and give family or colleagues their own logins. This guide is the 2026 version: pinned image tags, a compose file without the obsolete version: line, and all data in one folder you can back up.
At a glance
- You get: a working chat page at
http://localhost:3000with a local model, plus backups and an update routine. - Time needed: about 15 minutes, plus the model download.
- Difficulty: easy. You copy a few commands and one file.
- You need: Docker, a terminal, about 10 GB of free disk and 8 GB of RAM or more.
- Optional: an NVIDIA GPU for speed; a domain name only for the HTTPS section.
| What | Value (read on 2026-10-26) |
|---|---|
| Open WebUI | v0.12.4, released 2026-10-25 |
| Ollama | v0.40.11, released 2026-10-24 |
| Images used | ghcr.io/open-webui/open-webui:v0.12.4 and ollama/ollama:0.40.11 (both official) |
| Ports | 3000 on your computer (to Open WebUI), 11434 for Ollama (inside Docker only) |
| Docs | docs.openwebui.com and docs.ollama.com |
Which version, and why: we checked the issue tracker, discussions and Reddit. We found no repeated reports of install failures or data loss for the 0.12 series, so this guide uses the latest release. It is only one day old, so the evidence is thin. If your first start shows a database migration error, restore your backup and pin v0.12.3 instead.
How it fits together#
You talk to Open WebUI in your browser, and Open WebUI asks Ollama to run the model.
Not sure which compose variant to use? Follow this picture.
Before you start#
You need Docker with Compose v2 and a terminal.
| Linux | Windows | Mac | |
|---|---|---|---|
| Docker | Docker Engine with Compose v2 | Docker Desktop (WSL2 backend) | Docker Desktop |
| Command | docker compose | docker compose | docker compose |
| NVIDIA GPU | NVIDIA Container Toolkit | Check Docker Desktop's GPU docs | Not available in containers |
| AMD GPU | ollama/ollama:rocm image | Not covered here | Not available |
| Apple GPU | - | - | Use the native Ollama app |
Check your tools:
docker --version docker compose version
Checklist:
- [ ] Docker is running.
- [ ] Port 3000 is free on your computer.
- [ ] You have about 10 GB free disk for the images and one small model.
- [ ] You can restart your machine's Docker if you add GPU support.
Tested on 2026-10-26: not run on a test machine. Every command and tag was checked against the official docs and the public registries (the image tags exist), as described in Sources.
Windows note: the Open WebUI docs advise running Docker commands from the WSL terminal when you use Docker with WSL. Docker Desktop also works from PowerShell, and the commands below use it. If something odd happens, try the same commands in a WSL terminal.
Step 1: Create the folders and a secret key#
Make one folder for everything and put a random secret key in a private .env file.
The key keeps people logged in. If you leave it out, everyone is logged out whenever the container is recreated.
Linux#
mkdir -p ~/docker_volumes/open-webui/{ollama,open-webui}
cd ~/docker_volumes/open-webui
cat > .env <<EOF
DATA_ROOT=$HOME/docker_volumes/open-webui
WEBUI_SECRET_KEY=$(openssl rand -hex 32)
EOF
chmod 600 .env
Windows (PowerShell)#
$d = "$HOME\docker_volumes\open-webui"
New-Item -ItemType Directory -Force "$d\ollama","$d\open-webui" | Out-Null
Set-Location $d
$b = New-Object byte[] 32
[Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($b)
$key = -join ($b | ForEach-Object { '{0:x2}' -f $_ })
Set-Content .env "DATA_ROOT=$($d -replace '\\','/')`nWEBUI_SECRET_KEY=$key"
Mac (Terminal)#
Same as Linux:
mkdir -p ~/docker_volumes/open-webui/{ollama,open-webui}
cd ~/docker_volumes/open-webui
cat > .env <<EOF
DATA_ROOT=$HOME/docker_volumes/open-webui
WEBUI_SECRET_KEY=$(openssl rand -hex 32)
EOF
chmod 600 .env
Check it worked: ls -a (Windows: Get-ChildItem -Force) shows .env, ollama and open-webui. Never put .env in Git.
Step 2: Save the compose file#
Create docker-compose.yml in that folder. The file content is the same on all three systems, except the Mac note below. Save it with your editor, or with the commands here.
Linux#
Open docker-compose.yml in your editor (nano docker-compose.yml) and paste this:
services:
ollama:
image: ollama/ollama:0.40.11
container_name: ollama
restart: unless-stopped
volumes:
- ${DATA_ROOT}/ollama:/root/.ollama
# NVIDIA GPU (Linux): remove the # signs in front of the next 7 lines
# deploy:
# resources:
# reservations:
# devices:
# - driver: nvidia
# count: all
# capabilities: [gpu]
open-webui:
image: ghcr.io/open-webui/open-webui:v0.12.4
container_name: open-webui
restart: unless-stopped
depends_on:
- ollama
ports:
- "127.0.0.1:3000:8080"
environment:
- OLLAMA_BASE_URL=http://ollama:11434
- WEBUI_SECRET_KEY=${WEBUI_SECRET_KEY}
volumes:
- ${DATA_ROOT}/open-webui:/app/backend/data
Windows (PowerShell)#
Run notepad docker-compose.yml, paste the same content, and save it in $HOME\docker_volumes\open-webui. Make sure Notepad does not add .txt to the name.
Mac (Terminal)#
Same as Linux: nano docker-compose.yml, paste the same content, save.
What the important lines do:
| Line | Meaning |
|---|---|
ghcr.io/open-webui/open-webui:v0.12.4 | The official image, pinned. :main and :latest are rolling builds, not stable releases. |
127.0.0.1:3000:8080 | Only this computer can open the page. Remove 127.0.0.1: to allow your home network. |
OLLAMA_BASE_URL | Tells Open WebUI where Ollama is, by its service name. |
${DATA_ROOT}/... | Your data lives in ~/docker_volumes/open-webui, easy to back up. |
Mac: Docker on a Mac cannot use the Apple GPU, so Ollama in a container is CPU only. For real speed, install the native Ollama app, delete the whole ollama: service and the depends_on block, and set OLLAMA_BASE_URL=http://host.docker.internal:11434. This also works on Linux and Windows when Ollama runs on the host.
AMD GPU (Linux): use the image ollama/ollama:0.40.11-rocm (the tag exists) and pass the devices /dev/kfd and /dev/dri to the container, as the Ollama docs describe.
NVIDIA GPU (Linux): install the NVIDIA Container Toolkit, then run sudo nvidia-ctk runtime configure --runtime=docker and restart Docker. After that, uncomment the deploy: block above.
Step 3: Start it#
Start both containers and watch the log until Open WebUI is ready.
Linux#
docker compose up -d docker compose ps docker compose logs -f open-webui
Windows (PowerShell)#
docker compose up -d docker compose ps docker compose logs -f open-webui
Mac (Terminal)#
Same commands as Linux:
docker compose up -d docker compose ps docker compose logs -f open-webui
Check it worked: docker compose ps lists ollama and open-webui as running. Press Ctrl+C to leave the log. The first start can take a minute while the database is prepared.
Potential issue: if port 3000 is taken, change the left number in 127.0.0.1:3000:8080, for example to 3001.
Step 4: Download a model#
Pull one small model so you can chat right away.
Linux#
docker exec -it ollama ollama pull llama3.2 docker exec ollama ollama list
Windows (PowerShell)#
docker exec -it ollama ollama pull llama3.2 docker exec ollama ollama list
Mac (Terminal)#
Same commands as Linux, but if you use the native Ollama app, run ollama pull llama3.2 directly.
docker exec -it ollama ollama pull llama3.2 docker exec ollama ollama list
Check it worked: ollama list shows llama3.2. You can also pull models later from inside Open WebUI.
Step 5: First-run setup#
Open the page, create the admin account and pick your model.
Same on all three systems, in your browser:
Linux#
- Open
http://localhost:3000. - Click Get started and sign up. The first account becomes the administrator. Use a strong password and store it safely: if you lose it, a new account needs admin activation, so there is no easy way back (the docs have a password-reset guide).
- Open Admin Settings > Connections. The Ollama address should read
http://ollama:11434. - Choose
llama3.2in the model picker and send a message.
Windows (PowerShell)#
Same steps. Open http://localhost:3000 in your browser. Check the log with docker compose logs open-webui --tail 20.
Mac (Terminal)#
Same steps. If you use the native Ollama app, the connection address is http://host.docker.internal:11434.
Check it worked: the model answers, and docker compose logs open-webui --tail 20 shows no errors.
Put it behind HTTPS (with or without Traefik)#
With Traefik#
This section is only for a server with a domain name; if you use Open WebUI at home, skip it.
You need a domain pointing at your server, ports 80 and 443 open, and Traefik already running with a websecure entrypoint and a certificate resolver (here called letsencrypt). Create the shared network once if it is missing:
docker network create proxy
Change the open-webui service: remove ports: and add the lines below. The label names come from Traefik's Docker provider; the Open WebUI settings are from its docs. Adjust the entrypoint and resolver names to match your Traefik setup.
open-webui:
# ...image, volumes and the rest stay as before; delete the ports: block
networks: [proxy]
environment:
- OLLAMA_BASE_URL=http://ollama:11434
- WEBUI_SECRET_KEY=${WEBUI_SECRET_KEY}
- WEBUI_URL=https://ai.<your-domain>
- CORS_ALLOW_ORIGIN=https://ai.<your-domain>
- WEBUI_SESSION_COOKIE_SECURE=true
- WEBUI_AUTH_COOKIE_SECURE=true
labels:
- traefik.enable=true
- traefik.docker.network=proxy
- traefik.http.routers.owui.rule=Host(`ai.<your-domain>`)
- traefik.http.routers.owui.entrypoints=websecure
- traefik.http.routers.owui.tls=true
- traefik.http.routers.owui.tls.certresolver=letsencrypt
- traefik.http.services.owui.loadbalancer.server.port=8080
Also add the network at the bottom of the file, and keep ollama on the default network so it is never reachable from outside:
networks:
proxy:
external: true
Because open-webui now sits on proxy only, it can no longer reach ollama. Put it on both: networks: [proxy, default].
Open WebUI needs WebSocket support (Traefik does this by default). If streamed answers look garbled, check Traefik's compression and buffering middleware.
Without Traefik: Caddy#
Choose this if you have no Traefik yet and run one small server. Caddy is one small program that gets and renews certificates by itself.
| Your case | What Caddy does | What you do |
|---|---|---|
| Public domain | Automatic Let's Encrypt certificate | Point a DNS A record at the server; open ports 80 and 443 |
| Home only, no domain | tls internal: Caddy's own local certificate | Trust Caddy's root certificate on each device (below) |
Caddyfile for Open WebUI (it listens on 127.0.0.1:3000 in this guide):
ai.example.com {
reverse_proxy localhost:3000
}
Home-only variant (point the name ai.home.arpa at the server in your router, Pi-hole or hosts file):
ai.home.arpa {
tls internal
reverse_proxy localhost:3000
}
Run Caddy (Caddyfile in /etc/caddy/Caddyfile on Linux):
- Linux: install from the official apt repository (see caddyserver.com/docs/install), save the Caddyfile, then
sudo systemctl reload caddy. - Windows (PowerShell):
winget install CaddyServer.Caddy, thencaddy run --config Caddyfilein the folder with your Caddyfile. - Mac:
brew install caddy, thencaddy run --config Caddyfile. - Docker: add this service to the same compose file and put the Caddyfile in
~/docker_volumes/caddy/conf/(create it first: Linux/Macmkdir -p ~/docker_volumes/caddy/conf; Windows PowerShellNew-Item -ItemType Directory -Force "$HOME\docker_volumes\caddy\conf"). Inside Docker, usereverse_proxy open-webui:8080in the Caddyfile instead oflocalhost:3000.
caddy:
image: caddy:2.11.7
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ~/docker_volumes/caddy/conf:/etc/caddy:ro
- ~/docker_volumes/caddy/data:/data
Home-only: trust Caddy's root certificate. It is pki/authorities/local/root.crt in Caddy's data folder.
- Linux: on the Caddy machine run
sudo caddy trust. On other Linux devices copyroot.crtto/usr/local/share/ca-certificates/and runsudo update-ca-certificates. - Windows:
caddy trustin an administrator PowerShell on the Caddy machine. On other devices double-clickroot.crtand install it into "Trusted Root Certification Authorities". - Mac:
caddy truston the Caddy machine. On other Macs addroot.crtin Keychain Access and set it to "Always Trust".
Open WebUI streams answers over WebSockets; Caddy handles that by default. Set WEBUI_URL and CORS_ALLOW_ORIGIN in the compose file to the https address (for example https://ai.example.com), as in the Traefik example above.
Check it worked: curl -I https://ai.example.com answers HTTP/2 200.
Security and testing#
Keep it off the internet unless you have a reason, and protect the secret key.
| Do this | Why |
|---|---|
Keep 127.0.0.1: in the port mapping | Only your computer can open the page |
chmod 600 .env and keep it out of Git | It holds the secret key |
| For remote access, use a VPN such as WireGuard or Tailscale | Safer than opening port 3000 |
Never set WEBUI_AUTH=False on a shared machine | Single-user mode removes the login, and you cannot switch back to multi-user |
| Turn on two-factor sign-in if your version offers it | Added in v0.12.0 as ENABLE_MFA |
Tests:
docker compose ps
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:3000/
curl -s http://localhost:3000/api/config
You should get status 200 and a JSON answer. With Traefik: curl -I https://ai.<your-domain>. On Windows use curl.exe instead of curl.
Using it for RAG and web search#
Upload a document in a chat, and Open WebUI finds the relevant parts and gives them to the model.
The standard image bundles what RAG needs, so it works out of the box. The :slim image (about 197 MB against 1.62 GB for the standard one, per the docs on 2026-10-16) leaves embeddings, PDF reading and speech to external services. Without them, uploads fail with a 503 error. This guide uses the standard image.
- Chat with documents: click + in the chat and attach a file, or add files under Workspace > Knowledge.
- Web search: set a provider in Admin Settings > Web Search. On
:slimthe built-in DDGS provider is greyed out. - Tools for your model: to let a local model call tools, see our tool-server guide for Open WebUI.
Users and permissions#
Admins manage everything; everyone else gets only what you allow.
- Sign-ups: in Admin Settings decide whether new users can register and whether the admin must approve them.
- Groups: use Admin Settings > Groups to give people different permissions and model access.
- Hide controls: v0.12.4 added Visible controls (
UI_VISIBILITY) so you can hide single buttons from users. Admins still see everything. - Two-factor sign-in: optional since v0.12.0.
What changed since 2025#
The big ones are the licence, a desktop app and the 0.12 features.
| Change | What it means for you |
|---|---|
| Licence (since v0.6.6, 19 Apr 2025) | Code up to v0.6.5 stays BSD-3. Newer code adds a branding clause (below). |
| Desktop app | An "Early Alpha" native app exists for Windows and macOS with no Docker. It is an alternative, not a replacement. For a server, use Docker. |
| v0.12.x features | Realtime voice calls, two-factor sign-in, replies in shared chats, skills loaded on demand, hidden controls for users |
Image :slim | A small image that needs external services for RAG and speech |
| Image tags | :main and :latest are rolling; pin a vX.Y.Z tag |
The branding rule in plain words: do not change, remove or hide the "Open WebUI" name or logo. You may rebrand if you have 50 or fewer end users in a rolling 30 days, have written permission as a substantive contributor, or hold an enterprise licence. A small banner like "Managed by YourOrg" is allowed; "Powered by Open WebUI" alone as a rebrand is not. The 50 is not a user cap - it only decides whether you may rebrand. This is not legal advice.
Other layouts#
| You want | Change |
|---|---|
| Ollama already runs on the host | Delete the ollama: service, set OLLAMA_BASE_URL=http://host.docker.internal:11434, and add extra_hosts: ["host.docker.internal:host-gateway"] on Linux. Ollama must listen on 0.0.0.0 (OLLAMA_HOST). |
| Ollama on another machine | Set OLLAMA_BASE_URL=http://<server-address>:11434 |
| One all-in-one container | The ollama image variant exists, but separate containers let you pin and update each one |
| OpenAI-compatible cloud models too | Add the connection in Admin Settings > Connections |
Troubleshooting#
| Problem | Solution |
|---|---|
| Page says "Open WebUI backend required" | The browser could not reach the backend. Map to container port 8080, test curl http://localhost:3000/api/config, then open a private window |
| No models listed, cannot reach Ollama | Use http://ollama:11434 in Compose. For a host Ollama use host.docker.internal |
Connect call failed ('127.0.0.1', ...) | localhost inside the container is the container itself. Use a service name or host.docker.internal |
https://yourdomain.com is not an accepted origin | Add every address you use to CORS_ALLOW_ORIGIN, separated by semicolons |
Garbled ## and ** while streaming | Proxy buffering. In nginx set proxy_buffering off |
Model picker spins, /api/models returns 500 | An endpoint is unreachable. Remove it or lower AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST |
| Upload returns 503 | You use :slim without an external embedding service. Use the standard image |
no such table or table ... already exists | A migration did not finish. Stop, restore your backup, start again |
| GPU unused | Toolkit missing or Docker not restarted after nvidia-ctk runtime configure |
| Everyone logged out after recreating | WEBUI_SECRET_KEY is missing or changes. Keep it fixed in .env |
| Saved tool connections stop working after an update | ENABLE_DIRECT_INTEGRATIONS defaults to off. Enable it in Admin Settings > Integrations |
Self-signed certificates#
If you see [SSL: CERTIFICATE_VERIFY_FAILED] with a document parser, embedding service or web loader, set REQUESTS_VERIFY=false, AIOHTTP_CLIENT_SESSION_SSL=false or ENABLE_WEB_LOADER_SSL_VERIFICATION=false. Only do this on a network you trust.
Known bugs#
One failed-migration report (table chat has no column named timer_at, issue #29290, 31 Aug 2026) was on a dev build, not a stable release. The fix is the same: restore your backup.
Diagnostics#
docker compose ps docker logs open-webui --tail 100 docker logs ollama --tail 100 docker inspect open-webui
Updates and backups#
Back up first, then change the tag, pull and restart. Database migrations run at start-up and cannot be undone by rolling back the container, so the backup is your way back.
- Read the release notes.
- Make a backup (below).
- Edit the image tag in
docker-compose.yml. - Run
docker compose pull && docker compose up -d. - Check
docker compose logs open-webui --tail 20and log in.
Ollama v0.40.2 and later upgrade old models in the background and keep backup copies on disk. If you go back below 0.40, you must pull those models again.
Linux#
cd ~/docker_volumes/open-webui mkdir -p backups docker compose stop open-webui tar czf backups/owui-$(date +%F).tgz open-webui .env docker-compose.yml docker compose start open-webui
Schedule it every night at 03:00 with crontab -e:
0 3 * * * cd $HOME/docker_volumes/open-webui && docker compose stop open-webui && mkdir -p backups && tar czf backups/owui-$(date +\%F).tgz open-webui .env docker-compose.yml && docker compose start open-webui
Windows (PowerShell)#
Set-Location "$HOME\docker_volumes\open-webui" New-Item -ItemType Directory -Force backups | Out-Null docker compose stop open-webui tar -czf "backups\owui-$(Get-Date -Format yyyy-MM-dd).tgz" open-webui .env docker-compose.yml docker compose start open-webui
Run it every night with Task Scheduler: create a basic task at 03:00 that starts pwsh.exe with -File pointing to a script holding the lines above.
Mac (Terminal)#
Same commands as Linux. For the schedule, use crontab -e the same way.
Restore test#
A backup you never restored is a hope, not a backup. Unpack it into a scratch folder and start a throwaway copy on another port.
mkdir -p /tmp/restore && tar xzf backups/owui-*.tgz -C /tmp/restore docker run --rm -d --name owui-test -p 3100:8080 \ -e WEBUI_SECRET_KEY=test \ -v /tmp/restore/open-webui:/app/backend/data \ ghcr.io/open-webui/open-webui:v0.12.4
Open http://localhost:3100, log in with your normal account and check your chats. Then remove the test copy:
docker rm -f owui-test
On Windows, unpack with tar -xzf into a scratch folder and use that folder in the -v option. The Ollama folder holds large models you can pull again, so back it up only if your bandwidth is limited.
Performance and resources#
The model, not Open WebUI, uses most of your memory.
- Open WebUI itself is light: the docs measured about 300 MiB of RAM idle for the slim image on v0.12.3. That is not a minimum, and the standard image uses more.
- Pick a model that fits your GPU memory or RAM. A small 3B model runs on 8 GB; larger models need more.
- The
:cudaOpen WebUI image only moves Open WebUI's own embedding, reranking and speech models to the GPU. Ollama needs its own GPU access. - On a low-power machine with SQLite, keep
DATABASE_ENABLE_SESSION_SHARINGoff. - Watch usage live with:
docker stats
FAQ#
Is it free for a company? Yes, but keep the "Open WebUI" branding unless you have 50 or fewer end users, written permission, or an enterprise licence.
Why not use :main or :latest? They are rolling builds from the main branch, not stable releases. A pinned vX.Y.Z tag never changes under you.
Can I run it without Docker? Yes, with pip install open-webui on Python 3.11 or 3.12. Python 3.13 is not supported. Docker is the recommended way.
Will updating delete my chats? No, your data lives in the mounted folder. The risk is rolling back after a migration, so always keep a backup.
Should I use the all-in-one Ollama image? It works, but separate containers let you update and pin each program on its own, which is why this guide uses two.
Sources#
- Open WebUI Quick Start - read on 2026-10-26
- Open WebUI releases (v0.12.4, 2026-10-25) - read on 2026-10-26
- Open WebUI FAQ and troubleshooting - read on 2026-10-26
- Open WebUI desktop app - read on 2026-10-26
- Open WebUI licence - undated page, read on 2026-10-26; not legal advice
- Ollama Docker docs and Ollama releases (v0.40.11, 2026-10-24) - read on 2026-10-26
- Our tool-server guide for Open WebUI
- Caddy docs: automatic HTTPS, reverse_proxy, install - Caddy v2.11.7, image tag
caddy:2.11.7confirmed on Docker Hub, read on 2026-10-26
Checked against the official docs on 2026-10-26. Versions and release dates were confirmed with the GitHub API, and the image tags v0.12.4 (GHCR) and 0.40.11 and 0.40.11-rocm (Docker Hub) were confirmed to exist. Not run end to end by DIY Lab Hub. Items we could not confirm: whether Docker Desktop passes an NVIDIA GPU to containers on Windows (see Docker's GPU docs), and the Reddit and GitHub comment threads for 0.12.x, which were not read in full.