Home / AI & GenAI

AI & GenAIHow-toBeginner

Putting Open WebUI in front of vLLM or Ollama: an internal chat UI with sign-in, roles and no open signup

Deploy Open WebUI as the internal chat front end for a self-hosted model. Connect it to vLLM or Ollama, lock down signup and roles, add SSO, and back it up.

Deepak Bhardwaj7 min read

Applies toOpen WebUI (recent releases, ghcr.io/open-webui/open-webui:main), vLLM OpenAI-compatible server, Ollama, Docker / Docker Compose

Goal

You already run a model on vLLM or Ollama, and people want a chat UI for it. Open WebUI is the usual choice. If you run it with the defaults it works, but you get an open signup page and a few surprises when you change settings later. This guide sets it up so that:

  • it talks to your model server over the internal network only,
  • nobody can create an account without approval (or SSO),
  • the session signing key stays the same when the container is recreated,
  • the data volume is backed up and the service has a health check.

1. Check the model server first

Open WebUI only shows what the backend returns from its models endpoint. Test that before you touch the UI.

vLLM (OpenAI-compatible, started with --api-key):

curl -s http://vllm.internal:8000/v1/models -H "Authorization: Bearer $VLLM_API_KEY" | jq '.data[].id'

Ollama:

curl -s http://ollama.internal:11434/api/tags | jq '.models[].name'

If those calls fail, fix them first. Open WebUI will just show an empty model list.

2. Run Open WebUI with Docker Compose

services:
  open-webui:
    image: ghcr.io/open-webui/open-webui:main   # pin a release tag in production
    container_name: open-webui
    restart: always
    ports:
      - "127.0.0.1:3000:8080"                 # only the reverse proxy reaches it
    volumes:
      - open-webui:/app/backend/data
    environment:
      WEBUI_URL: "https://chat.internal.example.com"
      WEBUI_SECRET_KEY: "${WEBUI_SECRET_KEY}"
      # vLLM as an OpenAI-compatible backend
      ENABLE_OPENAI_API: "true"
      OPENAI_API_BASE_URL: "http://vllm.internal:8000/v1"
      OPENAI_API_KEY: "${VLLM_API_KEY}"
      # Turn Ollama off if you don't use it (or set OLLAMA_BASE_URL instead)
      ENABLE_OLLAMA_API: "false"
      # Accounts
      ENABLE_SIGNUP: "false"
      DEFAULT_USER_ROLE: "pending"
      ENABLE_COMMUNITY_SHARING: "false"
volumes:
  open-webui:

Generate the secret once and store it in your secret store, not in the compose file:

openssl rand -hex 32

For Ollama, swap the OpenAI block for:

      ENABLE_OLLAMA_API: "true"
      OLLAMA_BASE_URL: "http://ollama.internal:11434"
      ENABLE_OPENAI_API: "false"

For several backends, OPENAI_API_BASE_URLS and OPENAI_API_KEYS (and OLLAMA_BASE_URLS) take semicolon-separated lists in matching order.

Warning

WEBUI_SECRET_KEY signs login tokens and is used to encrypt stored data. Docker generates a random one on first start if you don't set it. If it changes, for example because the container is recreated somewhere it can't find the old key, everyone is logged out and encrypted settings may stop working. Set it yourself and keep it the same.

Create the admin account straight away

The first account registered becomes the admin. Start the container, open the URL right away and register the admin account yourself before you announce the service. Leave the port bound to 127.0.0.1 (as above) until you have done this.

3. Know which settings the environment controls

This catches most people out. Many Open WebUI settings are persistent config: on first start the environment value is written to the database, and from then on the database value wins. If you change ENABLE_SIGNUP or OPENAI_API_BASE_URL in compose later and restart, nothing happens.

You changed It didn't apply because Fix
ENABLE_SIGNUP, DEFAULT_USER_ROLE Value already stored in the database Change it in Admin Panel > Settings, or set ENABLE_PERSISTENT_CONFIG=false
OPENAI_API_BASE_URL, API keys Connection stored in the database Edit it under Admin Panel > Settings > Connections
OLLAMA_BASE_URL Not persistent, but the OLLAMA_BASE_URLS list may be Check Connections in the admin panel
WEBUI_AUTH=false Only allowed on a fresh install with no users Leave auth on. Don't run an internal UI without it

ENABLE_PERSISTENT_CONFIG=false makes the environment the source of truth on every start. That suits GitOps-managed deployments. Settings edited in the UI are then lost on restart, so pick one approach and write it down in the runbook.

4. Add SSO instead of local passwords

With OIDC (Entra ID, Okta, Keycloak and others), people sign in with their corporate account and leavers lose access when their account is disabled.

      ENABLE_OAUTH_SIGNUP: "true"
      OAUTH_PROVIDER_NAME: "Corporate SSO"
      OPENID_PROVIDER_URL: "https://login.microsoftonline.com/<tenant-id>/v2.0/.well-known/openid-configuration"
      OAUTH_CLIENT_ID: "${OIDC_CLIENT_ID}"
      OAUTH_CLIENT_SECRET: "${OIDC_CLIENT_SECRET}"
      ENABLE_LOGIN_FORM: "false"        # after you have confirmed an SSO admin can sign in

Register the redirect URI with your identity provider. Its path is in the Open WebUI SSO docs for your version, so check it there. WEBUI_URL must be set to the public HTTPS address before OAuth will work.

Caution

Don't turn off ENABLE_LOGIN_FORM until an SSO account has signed in and has the admin role. Otherwise you can lock yourself out of the admin panel.

ENABLE_OAUTH_SIGNUP=true creates accounts on first SSO login. Together with DEFAULT_USER_ROLE=pending, an admin still has to approve each new account. To open it to everyone in the tenant, restrict access in the identity provider (assigned users only) and set the default role to user.

5. Control who sees which models

  • Keep BYPASS_MODEL_ACCESS_CONTROL at its default (false). When it is true, every user can use every model.
  • Set model visibility and group access in the admin panel. The menu names have changed between releases, so look under Admin Panel > Settings > Models or Workspace > Models.
  • API keys for users are off by default (ENABLE_API_KEYS=false). Leave them off unless you need them. Otherwise the UI becomes an unmetered side door to your GPU.

6. Reverse proxy, streaming and health checks

Open WebUI uses WebSockets and streams tokens, so the proxy must pass both through:

location / {
    proxy_pass http://127.0.0.1:3000;
    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-Forwarded-Proto $scheme;
    proxy_buffering off;
    proxy_read_timeout 300s;
}

Health check for the load balancer or monitoring. It needs no login and returns 200 when the app and its database respond:

curl -fsS http://127.0.0.1:3000/health

/health doesn't tell you whether the model backend is reachable. For that, monitor the vLLM or Ollama endpoint directly with the calls from step 1.

7. Back up the data volume

Users, chats, settings and uploaded files live in /app/backend/data (SQLite by default). Back it up while the container is stopped, or during a quiet window:

docker stop open-webui
docker run --rm -v open-webui:/data -v "$PWD":/backup alpine \
  tar czf /backup/open-webui-$(date +%F).tgz -C /data .
docker start open-webui

If you have many users, a PostgreSQL database (DATABASE_URL) is easier to back up and run highly available. Check the docs for your version before you migrate.

Troubleshooting quick reference

Symptom Likely cause Check
Model list is empty Wrong base URL, missing /v1, bad API key docker logs open-webui, then the curl calls from step 1 from inside the container
Answers appear all at once Proxy buffering proxy_buffering off, and check any gateway in between
"Connection lost" or the UI keeps reconnecting WebSocket upgrade blocked Upgrade/Connection headers on the proxy
Everyone logged out after a redeploy WEBUI_SECRET_KEY changed Set a fixed key from your secret store
Env change ignored Persistent config Section 3

Prevent it next time

  • Pin an image tag instead of :main, and test upgrades on a copy of the data volume first.
  • Keep the container port bound to localhost or a private network. Only the proxy should be exposed.
  • Keep WEBUI_SECRET_KEY, the backend API key and the OIDC secret in a secret store, and include them in your restore test.
  • Review pending users and admin role holders monthly.
  • Alert separately on /health and on the model backend, so you can tell whether the UI or the model is down.