To install Open WebUI with Docker, pull ghcr.io/open-webui/open-webui:main and run it with -p 3000:8080 and a named volume at /app/backend/data, then open http://localhost:3000 and create the admin account. The container listens on port 8080; 3000 is only the host side. Docker Compose works the same way, and Docker is the officially recommended install method.
The whole application ships as one image. The project documents Python, Kubernetes, Podman and desktop paths as well, but the container route is the one where the fewest things can go wrong, provided you understand three decisions the install command quietly makes for you: which image tag you pulled, where your data lives, and which model backend the container can reach.
What you are actually installing
The official image is a single process that serves the web interface and the API together on container port 8080. That matters more than it sounds. When people report the “Open WebUI backend required” error, the usual cause is a port mapping that points at something other than 8080 inside the container, so the browser gets the interface shell but the interface’s own request to /api/config never reaches the backend.
The container does not include a language model. Unless you deliberately choose the bundled image, the model backend is a separate process that the container reaches over HTTP. If you want the background on that split before configuring anything, how Open WebUI and local models fit together covers which component owns which behaviour.
The command, flag by flag
The documented starting point in the official quick start pulls the image and runs it:
docker pull ghcr.io/open-webui/open-webui:main
docker run -d -p 3000:8080 --add-host=host.docker.internal:host-gateway \
-v open-webui:/app/backend/data -e WEBUI_SECRET_KEY=your-secret-key \
--name open-webui --restart always ghcr.io/open-webui/open-webui:main
The pull is the slow step: the standard image is 1.54 GB compressed on amd64.
-p 3000:8080 publishes the interface on port 3000 of the host and maps it to the container’s 8080. -v open-webui:/app/backend/data mounts a named Docker volume at the application’s data directory, which is the single thing standing between you and losing every account, conversation and indexed document the next time the container is recreated. The interface then answers at http://localhost:3000.
--add-host=host.docker.internal:host-gateway lets the container reach the host by name, and http://host.docker.internal:11434 is the documented Docker default for OLLAMA_BASE_URL, so a same-host Ollama is found without more configuration. Replace your-secret-key with the output of openssl rand -hex 32 so logins survive restarts. --restart always is covered under start and stop below.
One network requirement is easy to miss. WebSocket support is required from v0.5.0 onwards. A direct install on a local machine has this by default, but a proxy or corporate network that blocks upgrade requests produces a chat that hangs with no obvious error.
Install Open WebUI with Docker Compose
Docker Compose runs the same image from a file instead of a long command. Save the quick start’s service definition as docker-compose.yml, replace the secret with the output of openssl rand -hex 32, and run docker compose up -d in that directory. The interface appears on http://localhost:3000, exactly as with docker run.
services:
open-webui:
image: ghcr.io/open-webui/open-webui:main
ports:
- "3000:8080"
volumes:
- open-webui:/app/backend/data
extra_hosts:
- host.docker.internal:host-gateway
environment:
- WEBUI_SECRET_KEY=your-secret-key
restart: unless-stopped
volumes:
open-webui:
extra_hosts is the Compose form of --add-host. The project’s own compose file goes further, adding an ollama service with an ollama:/root/.ollama volume and pointing OLLAMA_BASE_URL at http://ollama:11434, the service name rather than localhost.
Avoid docker compose down -v unless you mean it. Plain down removes the containers and network, but -v also removes named volumes, and here that volume is your whole instance. To update, run docker compose pull then docker compose up -d, after the backup step in the container update guide.
Open WebUI port: 8080 inside, 3000 outside
Open WebUI listens on port 8080 inside the container, and the documented Docker command publishes it on host port 3000, so you browse to http://localhost:3000. Python and desktop-app installs answer on 8080 directly. To use another host port, change only the left number in -p 3000:8080; the right number must stay 8080.
| Setup | Port you open | Change it with |
|---|---|---|
docker run -p 3000:8080 or quick start Compose | 3000 | Left number of the mapping |
| Compose, repository file | 3000 | OPEN_WEBUI_PORT |
docker run --network=host | 8080 | -e PORT=... |
Python, open-webui serve | 8080 | --port flag |
If 3000 is taken, -p 3001:8080 moves the host side. -p 127.0.0.1:3000:8080 binds it to loopback only, keeping the instance off the network; the docker run reference documents that form. Host networking has no mapping, so a maintainer’s GitHub answer is -e PORT=1234. Port 11434 is Ollama’s, not Open WebUI’s.
Open WebUI on Docker Hub vs ghcr.io
Pull from ghcr.io/open-webui/open-webui unless you have a reason not to. Docker Hub’s openwebui/open-webui mirrors the same images but only a subset of tags, and the quick start states that :main, :dev, :vX.Y.Z and :git-<sha> exist on ghcr.io only. A command rewritten as openwebui/open-webui:main therefore has no tag to pull. On Docker Hub the standard image is latest:
docker pull openwebui/open-webui:latest
Variants drop the main- prefix (slim, cuda, ollama, plus latest-slim and similar), and releases appear as X.Y.Z and X.Y. Docker Hub lists amd64 and arm64 builds for each.
Choosing an image tag
The tag decides how the instance behaves over months, not just at install time. Sizes are Docker Hub’s compressed amd64 figures for the v0.11.4 builds, checked in September 2026.
| ghcr.io tag | Docker Hub tag | What it gives you | Moves over time | Size |
|---|---|---|---|---|
:main / :latest | latest | Standard image, newest build of the main branch | Yes, rolling | 1.54 GB |
:main-slim | slim | Local machine-learning stack removed | Yes, rolling | 168 MB |
:cuda | cuda | NVIDIA GPU support (CUDA 12.8), used with --gpus all | Yes, rolling | 5.18 GB |
:cuda126 | cuda126 | Same as :cuda, built against CUDA 12.6 | Yes, rolling | 4.68 GB |
:ollama | ollama | Open WebUI and Ollama bundled in one container | Yes, rolling | 3.11 GB |
:vX.Y.Z, :X.Y.Z | X.Y.Z | One pinned stable release | No | 1.54 GB (0.11.4) |
:X.Y | X.Y | Newest patch release of that minor line | Yes, within the minor | 1.54 GB (0.11) |
:git-<sha> | Not mirrored | One exact commit | No | n/a |
:dev | Not mirrored | Newest build of the dev branch | Yes, rolling | n/a |
Two points repay attention. First, :latest follows the main branch rather than the newest stable release, so it is not the conservative choice its name suggests; the documentation is explicit that production deployments should pin a version tag. Second, :dev builds can carry database migrations that are not backward compatible, so the project warns against ever sharing a data volume between a dev and a production instance. Give dev its own volume or do not run it at all.
:main-slim shrank to around 175 MB in v0.11.4, and the release notes explain the cost: no embedding or reranking model, so knowledge needs external embeddings, and PDF or Word uploads fail without an external document extractor. The quick start adds that local Whisper is not offered either.
GPU and bundled variants are just longer forms of the same command:
docker run -d -p 3000:8080 --gpus all -v open-webui:/app/backend/data \
--name open-webui ghcr.io/open-webui/open-webui:cuda
docker run -d -p 3000:8080 --gpus=all -v ollama:/root/.ollama \
-v open-webui:/app/backend/data --name open-webui --restart always \
ghcr.io/open-webui/open-webui:ollama
The bundled :ollama image is the shortest path to a working stack on one machine, at the cost of coupling two upgrade cycles together. Note that it mounts a second volume for the models, because model weights are large and you do not want to re-download them on every container recreate.
The volume is the application
Everything stateful lives in /app/backend/data: the SQLite database with accounts, conversations, prompts and settings, plus uploaded files and the vector store. A named volume survives docker rm and image updates; a container started without -v keeps that data inside the writable container layer, where it is deleted the moment the container is removed. Docker’s own documentation treats named volumes as the preferred mechanism for exactly this reason.
Two habits follow. Back up the volume on a schedule rather than trusting the container. And before any major version upgrade, take a copy of it, because a failed migration is far easier to recover from a snapshot than from an interrupted upgrade.
First start, and the account decision
The first account registered becomes the administrator. Create it immediately after the first start rather than leaving a fresh instance reachable, particularly on any host that is not strictly local.
Authentication can be disabled entirely with WEBUI_AUTH=False for a genuinely single-user setup, and the documentation carries a warning worth repeating: you cannot switch between single-user mode and multi-account mode after making that change. Treat it as a one-way door and pick deliberately.
Pointing the container at a model backend
localhost inside a container means the container, not the host, which is the single most common cause of an install that starts cleanly and then shows an empty model list. Name an address the backend can actually reach instead. If Ollama runs on the same host as the container, that address is host.docker.internal:
docker run -d -p 3000:8080 --add-host=host.docker.internal:host-gateway \
-e OLLAMA_BASE_URL=http://host.docker.internal:11434 \
-v open-webui:/app/backend/data --name open-webui --restart always \
ghcr.io/open-webui/open-webui:main
If Ollama runs on a different machine, point the variable at that machine instead, which is the form the documentation gives for a remote backend:
docker run -d -p 3000:8080 -e OLLAMA_BASE_URL=https://example.com \
-v open-webui:/app/backend/data --name open-webui --restart always \
ghcr.io/open-webui/open-webui:main
The documented alternative for a same-host setup is host networking, which also changes the port you connect to:
docker run -d --network=host -v open-webui:/app/backend/data \
-e OLLAMA_BASE_URL=http://127.0.0.1:11434 --name open-webui \
--restart always ghcr.io/open-webui/open-webui:main
With --network=host there is no port mapping, so the interface answers on 8080 rather than 3000. If the model list still comes back empty after this, work through Open WebUI not connecting to Ollama, which covers interface binding, saved configuration that overrides environment variables, and the timeout that makes an unreachable endpoint look like a slow one.
Ollama is only one option. The provider guide lists OpenAI, Anthropic and OpenAI-compatible services alongside local servers such as llama.cpp and vLLM, each added as a URL and API key under Settings > Admin > Connections.
Start, stop and restart the container
docker start open-webui starts an existing, stopped Open WebUI container with the flags it was created with, so its ports, volume and environment come back unchanged. Use it rather than re-running docker run, which creates a new container.
docker start open-webui
docker stop open-webui
docker restart open-webui
docker logs -f open-webui
docker stop sends SIGTERM, then kills the process after 10 seconds on Linux. Check docker logs -f if the interface does not return. With Compose, docker compose up -d in the project directory does the same job as start.
Whether you need to start it by hand after a reboot depends on the restart policy:
| Restart policy | After a crash | After a host reboot | After a manual docker stop |
|---|---|---|---|
no (default, no flag given) | Stays down | Stays down | Stays down |
always (quick start docker run) | Restarts | Restarts | Comes back when the daemon restarts |
unless-stopped (quick start Compose) | Restarts | Restarts | Stays down, even after a daemon restart |
How to use Open WebUI after installation
The official quick start continues from a running container to the first conversation:
- Open
http://localhost:3000for the bridged Docker commands above, orhttp://localhost:8080for host networking. Sign in with the administrator account created at first start. - Open your avatar menu, then Settings > Admin > Connections. Confirm that the Ollama connection points to the server configured above. These settings apply to the instance; personal settings control your own interface preferences.
- Make sure that server has a model. The quick start documents downloading one as the administrator by entering its name in a new chat’s model selector and confirming the pull. Wait for the download before expecting it to answer.
- Click New Chat, select the model in the message box, type a short prompt, and press Enter. A completed reply confirms that this conversation reached a working model backend.
Once basic chat works, use the Open WebUI document upload guide to work through file extraction and retrieval. Keep the Open WebUI and local model architecture guide nearby when deciding whether a symptom belongs to the interface, connection or model server.
Size the machine before you pull models
The container itself is small. The memory question is entirely about the backend: model weights at your chosen quantization, the KV cache for the context length you configure, and an embedding model if you plan to use document retrieval, all resident at once. The Open WebUI VRAM and RAG sizer gives a starting estimate for a parameter count, quantization and context window before you commit to hardware or to a model that will spill into system RAM and crawl.
Behind a reverse proxy
A local-only instance needs none of this. The moment it sits behind TLS and a proxy, the documentation lists a specific set of settings, and skipping them produces symptoms that look like application bugs:
WEBUI_URLset to the real external URL, ideally before first startup. It is a persistent config value, so changing it later means the admin panel or a temporaryENABLE_PERSISTENT_CONFIG=false.CORS_ALLOW_ORIGINlisting every origin users actually reach the instance through, semicolon separated. WebSocket connections respect CORS, so an incomplete list breaks chat rather than just logging a warning.WEBUI_SESSION_COOKIE_SECUREandWEBUI_AUTH_COOKIE_SECUREenabled for HTTPS.- Upgrade and Connection headers forwarded, with
proxy_http_version 1.1on nginx. proxy_buffering offandproxy_cache offon nginx. With buffering on, the proxy re-chunks the streamed response and splits markdown tokens across chunk boundaries, which is why replies arrive with visible**and broken formatting that disappears when streaming is turned off.
Updating without losing anything
Updating a container means replacing it, not patching it. The documented manual sequence is to pull the new image, remove the old container, and run the same command again; the named volume carries the state across. Watchtower automates the same replacement if you prefer.
Neither approach protects you from a bad release. Pinning a version tag and updating deliberately does, and it turns “the interface changed overnight” into a decision you made.
Follow how to update the Open WebUI container for the backup, replacement and rollback sequence.
A short pre-flight checklist
- Named volume mounted at
/app/backend/data, and a backup routine for it. - Host port mapped to container port 8080, unless you chose host networking.
- Image tag chosen on purpose: pinned for anything that matters, rolling only for a scratch instance.
- A fixed
WEBUI_SECRET_KEY, generated once and reused on every recreate. - Admin account created at first start.
- Model backend reachable from inside the container, not just from your browser.
- Reverse proxy settings applied before exposing it beyond the local network.
If you are still deciding whether Open WebUI is the right front end at all, Open WebUI compared with LibreChat sets the two stacks side by side on architecture, configuration model and licensing.
FAQ
can i run open webui in docker without ollama
Yes. Ollama is one backend among several. The provider guide lists OpenAI, Anthropic and OpenAI-compatible services such as Groq, Mistral and OpenRouter, plus local servers like llama.cpp, vLLM and LM Studio. Run the standard image as usual, then add the provider’s URL and API key under Settings, Admin, Connections in the interface.
how do i change the open webui port in docker compose
Edit the left side of the ports entry, for example "8081:8080", then run docker compose up -d so Compose recreates the container with the new mapping. Leave 8080 on the right, because that is where Open WebUI listens inside. The repository’s compose file reads the host port from OPEN_WEBUI_PORT instead.
why does open webui log me out after the container is recreated
Without a fixed WEBUI_SECRET_KEY, sessions do not survive the container being replaced, so an update or recreate signs everyone out. The quick start sets one for that reason. Generate a value once with openssl rand -hex 32, pass it with -e WEBUI_SECRET_KEY= or in the Compose environment block, and reuse it on every run.