If you need to know how to change Open WebUI port settings in Docker, edit only the host side of the mapping: -p 3000:8080 becomes -p 8081:8080, then recreate the container. Leave the right-hand 8080 alone, because that is where Open WebUI listens. Host networking uses -e PORT=8081, and a pip install uses open-webui serve --port 8081.
The usual trigger is mundane. Something else on the box already holds 3000, Docker refuses to start the container with “port is already allocated”, and the instinct is to change both numbers. That instinct produces the worst failure mode available: a login page that loads and an API that answers nothing.
Which number do you change, 3000 or 8080?
Change 3000, the left number. Docker’s syntax is host-port:container-port, per the port publishing docs, so -p 3000:8080 means “accept on host port 3000, forward to 8080 inside the container.” The image’s Dockerfile sets PORT=8080 and health-checks that port, so the container side is the fixed point.
The connection troubleshooting page is blunt about getting it wrong: mapping to any other internal port “breaks the API while still potentially serving cached assets.” You get the interface shell, then an “Open WebUI backend required” error because the browser’s request to /api/config lands on nothing.
| Install method | Default URL | What to change |
|---|---|---|
docker run quick start | http://localhost:3000 | Left side of -p |
| Compose, your own file | http://localhost:3000 | Left side of ports |
| Compose, repository file | http://localhost:3000 | OPEN_WEBUI_PORT |
docker run --network=host | http://localhost:8080 | -e PORT= |
pip or uv, open-webui serve | http://localhost:8080 | --port flag |
| Helm chart | Service port 80 | service.port |
How do you change the port on an existing docker run container?
Remove the container and run it again with the new mapping. Docker cannot edit a published port in place: docker container update only changes CPU, memory, block IO, PID limits and the restart policy. Recreating is safe as long as you mount the same named volume, because accounts, chats and settings live in /app/backend/data, not in the container.
Before removing anything, dump what the old container was started with, so the new one matches:
docker inspect --format '{{json .HostConfig.PortBindings}}' open-webui
docker inspect --format '{{json .Config.Env}}' open-webui
docker inspect --format '{{json .Mounts}}' open-webui
Then swap it:
docker stop open-webui && docker rm open-webui
docker run -d -p 127.0.0.1:8081:8080 \
--add-host=host.docker.internal:host-gateway \
-v open-webui:/app/backend/data \
-e WEBUI_SECRET_KEY=your-existing-secret \
--name open-webui --restart always \
ghcr.io/open-webui/open-webui:main
Two details in that command earn their place. First, WEBUI_SECRET_KEY: the environment reference notes that a recreated container without a persisted key generates a new one, which logs every user out and breaks stored OAuth tokens. Reuse the value from the inspect output, or set one now. Take a volume backup first if the instance matters; the container update guide has the backup and rollback steps for exactly this remove-and-recreate cycle.
Second, the 127.0.0.1: prefix. Docker’s firewall documentation states that published-port traffic is diverted in the nat table before ufw’s rules run, “effectively ignoring your firewall configuration.” A ufw deny 8081 does not protect a port Docker published on all interfaces. Binding to loopback does, and a reverse proxy can still reach it.
How do you change the Open WebUI port in Docker Compose?
Edit the left side of the ports entry and run docker compose up -d. Compose sees the changed service definition and, per the compose up reference, stops and recreates the container “preserving mounted volumes.” You do not need down first, and you never want down -v, which deletes the volume holding the whole instance.
services:
open-webui:
image: ghcr.io/open-webui/open-webui:main
ports:
- "127.0.0.1:8081:8080"
volumes:
- open-webui:/app/backend/data
environment:
- WEBUI_SECRET_KEY=your-existing-secret
restart: unless-stopped
volumes:
open-webui:
The project’s own docker-compose.yaml parameterises the host side as ${OPEN_WEBUI_PORT-3000}:8080, so with that file you can leave the YAML alone and set the port in a .env file beside it:
# .env, in the same directory as docker-compose.yaml
OPEN_WEBUI_PORT=8081
Two interpolation traps, both from Compose’s variable rules. A variable exported in your shell beats the .env file, so a stale export OPEN_WEBUI_PORT=... in your profile silently wins. And the single-dash form ${VAR-default} falls back only when the variable is unset; OPEN_WEBUI_PORT= with an empty value counts as set, so the 3000 default never applies. Run docker compose config to print the mapping Compose will actually use before you bring it up.
Host networking: set PORT instead
With --network=host there is no mapping to edit. Docker’s host driver docs say -p and --publish “are ignored, producing a warning instead,” so the only lever is the port the process binds. The image’s start.sh reads PORT="${PORT:-8080}" and passes it to uvicorn, and an answer in GitHub discussion 1559 gives exactly this fix:
docker run -d --network=host \
-v open-webui:/app/backend/data \
-e OLLAMA_BASE_URL=http://127.0.0.1:11434 \
-e PORT=8081 -e HOST=127.0.0.1 \
--name open-webui --restart always \
ghcr.io/open-webui/open-webui:main
The same script reads HOST, defaulting to 0.0.0.0, so HOST=127.0.0.1 keeps a host-networked instance on loopback. The Dockerfile’s health check probes http://localhost:${PORT:-8080}/health, so it follows the new port without extra work.
Do not carry this habit back into bridge mode. -e PORT=8081 -p 3000:8080 moves the server to 8081 inside the container while Docker keeps forwarding to 8080, where nothing listens.
Python, pip and uv installs: use —port
Pass --port to open-webui serve. The environment reference is explicit that PORT does not apply here: with open-webui serve, “you must specify it directly as a command-line argument using the --port flag.” The command’s source defines two options, host defaulting to 0.0.0.0 and port defaulting to 8080.
open-webui serve --port 8081 --host 127.0.0.1
# uv, with the quick start's DATA_DIR
DATA_DIR=~/.open-webui uvx --python 3.11 open-webui serve --port 8081
If a systemd unit starts it, the flag belongs in ExecStart, not in an Environment=PORT= line, for the same reason.
Kubernetes with the Helm chart
The official chart splits the two numbers the way Docker does. In its values.yaml, service.port (default 80) is what the cluster sees and service.containerPort (default 8080) is the pod’s listener. Change service.port, or service.nodePort when the type is NodePort, and leave containerPort at 8080.
service:
type: ClusterIP
port: 8081
containerPort: 8080
What else needs the new port
The listener is half the job. Anything that stored the old URL has to be updated too, or the instance comes up on the new port and still misbehaves.
- Reverse proxy upstream. An nginx
proxy_passor Caddyreverse_proxypointing at127.0.0.1:3000needs the new number. Users behind the proxy never see the change. - WEBUI_URL. It is a persistent config value, so editing the environment variable on an existing install may not take effect. The connection docs point to Settings > Admin > General > WebUI URL on a running instance. OAuth and SSO redirects depend on it.
- CORS_ALLOW_ORIGIN. The default is
*, per the hardening guide. If you narrowed it, the connection docs say to list every access path “in http and https with the correct ports.” A stale port there breaks WebSockets, and chats hang rather than error. - Ollama is not involved. Port 11434 belongs to Ollama and is reached through
OLLAMA_BASE_URL. Moving Open WebUI from 3000 to 8081 does not touch it. If models disappear afterwards, the cause is elsewhere; Open WebUI not connecting to Ollama works through it.
How do you confirm the new port works?
Query the API, not the page. docker ps should show the new binding in the PORTS column, for example 127.0.0.1:8081->8080/tcp, but a cached frontend can render even when the backend is unreachable, so the browser is a poor test.
curl -s http://localhost:8081/api/config | head -c 200
curl -s http://localhost:8081/health
JSON back from /api/config means the backend is reachable, per the connection troubleshooting page, and /health should report status as true, the same check the image’s health check runs. A connection reset or empty reply means nothing is listening behind the mapping, usually because the right-hand number is not the port Open WebUI bound. If Docker refuses to start with “port is already allocated”, find the holder with ss -ltnp | grep 8081 on Linux or lsof -iTCP:8081 -sTCP:LISTEN on macOS, then pick another number.
For the full set of first-run flags around this command, see installing Open WebUI with Docker.
FAQ
What port does Open WebUI use by default?
Open WebUI listens on port 8080 by default, both inside the official container and when started with open-webui serve. The Docker quick start publishes that container port on host port 3000, which is why most guides send you to localhost:3000. Port 11434, which appears in the same configs, belongs to Ollama, not Open WebUI.
How do I run Open WebUI on port 80?
Map host port 80 to the container’s 8080 with -p 80:8080, or run a reverse proxy on 80 and 443 in front of a higher port. Rootless Docker refuses ports below 1024; its troubleshooting page suggests an unprivileged port or lowering net.ipv4.ip_unprivileged_port_start, so the proxy route is usually simpler.
Will changing the Open WebUI port delete my chats?
No, provided the new container mounts the same volume at /app/backend/data. Accounts, conversations, uploads and settings live in that volume rather than in the container, so recreating it with a different port mapping keeps everything. Starting the new container without the -v flag gives you an empty instance instead.
Why does Open WebUI say backend required after changing the port?
The container side of the mapping no longer points at the port Open WebUI listens on. Changing -p 3000:8080 to -p 8081:8081, or setting PORT without host networking, lets the page load from cache while /api/config fails. Put 8080 back on the right side, recreate the container, and clear the site data.