Why add Open-WebUI to your Ollama server
Ollama exposes a REST API compatible with OpenAI — efficient for developers, inaccessible for other team members. Open-WebUI bridges that gap: a complete web interface that connects to Ollama (or any OpenAI-compatible provider) and turns an inference server into a collaborative tool.
The repository has passed 155,000 GitHub stars. Mind the licence: it is not MIT. The project ships its own licence, a three-clause BSD with one extra condition: beyond 50 users over a rolling 30 days, you may not alter or remove the "Open WebUI" branding unless you have written permission or an enterprise licence. For a small team nothing changes; beyond that, read the LICENSE file before customising the interface. Ollama, for its part, announced a 65 million dollar Series B in July 2026, a sign that the inference engine is settling into development teams for the long term.
The project is continuously maintained and publishes stable tags at a steady pace: version 0.13.0 dates from 3 November 2026. The pace has a downside, since default behaviours change from one minor version to the next (native tool calling became the default in 0.10.0). Hence the value of pinning a tag and reading the release notes before every update. Open-WebUI covers needs well beyond chat: RAG on local files, management of multiple models, user groups, web search and SSO integration via OpenID Connect.
What Open-WebUI concretely adds to your Ollama stack
- Multi-user interface: each team member has their own account, history and conversations — without access to the raw API or command line.
- Native RAG: import PDF, Markdown or Word files directly from the interface; Open-WebUI indexes them and injects them into each conversation's context.
- Model management: download, delete and activate Ollama models from the web interface, without going through
docker exec. - OpenID Connect SSO: connect Open-WebUI to your identity provider (Keycloak, Authentik, Google Workspace…) for unified access and centralised revocation.
- Groups and roles: define who can access which models, who can upload files, who has administration rights.
- No cloud dependency: all tokens, conversations and files stay on your infrastructure.
Hardware and software requirements
Open-WebUI runs in a Docker container and connects to Ollama via the internal Docker network. Both can coexist on the same VPS.
For a team of 5 to 10 people with quantised 7B models (Q4), plan for at minimum:
- 8 GB RAM (6 GB for the model + headroom for Open-WebUI and the system)
- 4 vCPU: CPU inference is slow with fewer cores; move to 8 vCPU for comfortable daily use
- 30 GB SSD storage minimum, plus space for your models (a 7B Q4 model ≈ 4.5 GB, a 13B model ≈ 8 GB)
- Docker and Docker Compose installed
- A domain name pointing to your VPS (required for TLS and SSO)
- A reverse proxy with HTTPS — Nginx, Traefik or Caddy (served over HTTP on a non-local domain or IP, Open-WebUI loses features in the browser: see troubleshooting)
If Ollama is already deployed on your VPS (see the article How to host Ollama on a VPS), you can skip directly to the Open-WebUI installation.
Deploy Open-WebUI and Ollama with Docker Compose
Create the Docker Compose file
Create a working directory then write the compose file:
mkdir -p /opt/openwebui && cd /opt/openwebuiContent of
compose.yml:services: ollama: image: ollama/ollama:latest container_name: ollama volumes: - ollama_data:/root/.ollama restart: unless-stopped open-webui: image: ghcr.io/open-webui/open-webui:main container_name: open-webui depends_on: - ollama ports: - "127.0.0.1:3000:8080" environment: - OLLAMA_BASE_URL=http://ollama:11434 - WEBUI_SECRET_KEY=${WEBUI_SECRET_KEY} volumes: - open_webui_data:/app/backend/data restart: unless-stopped volumes: ollama_data: open_webui_data:The
WEBUI_SECRET_KEYmust be a long random string, never written in the compose file: generate it withecho "WEBUI_SECRET_KEY=$(openssl rand -hex 32)" > .env && chmod 600 .env. Docker Compose reads this.envfile from the directory and substitutes${WEBUI_SECRET_KEY}.Start the stack
Start both services:
docker compose up -dCheck that both containers are active:
docker compose psOllama may take a few seconds to start. Open-WebUI waits for Ollama to be ready thanks to
depends_on, but if you see connection errors on first start, wait 15 seconds and reload.Download a first model
From the host, download a model via Ollama:
docker exec -it ollama ollama pull llama3.1:8bYou can also do it from the Open-WebUI interface once logged in, under Administration Panel → Models → Download from Ollama.com.
Configure the Nginx reverse proxy with HTTPS
Open-WebUI listens on
127.0.0.1:3000. Create an Nginx virtual host to expose it over HTTPS:server { listen 443 ssl; server_name openwebui.yourdomain.com; ssl_certificate /etc/letsencrypt/live/openwebui.yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/openwebui.yourdomain.com/privkey.pem; location / { proxy_pass http://127.0.0.1:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # WebSocket (required for response streaming) proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 300s; } }Obtain the certificate with Certbot:
certbot --nginx -d openwebui.yourdomain.comCreate the administrator account
Open
https://openwebui.yourdomain.comin your browser. The first account created automatically becomes administrator: create it as soon as the site is online, before anyone else does. Enter an email and password.From the administration panel (avatar icon → Administration Panel), you can:
- define whether new registrants are immediately active or pending validation;
- create user groups and associate models with them;
- configure SSO.
Configure OpenID Connect SSO
Open-WebUI natively supports authentication via OpenID Connect (OIDC). You can integrate it with Keycloak, Authentik, Authelia, or any compatible provider (including Google Workspace or Microsoft Entra).
In compose.yml, add the following environment variables to the open-webui service:
environment:
- OAUTH_CLIENT_ID=your-client-id
- OAUTH_CLIENT_SECRET=${OAUTH_CLIENT_SECRET}
- OPENID_PROVIDER_URL=https://your-idp.example.com/.well-known/openid-configuration
- OAUTH_PROVIDER_NAME=My SSO
- ENABLE_OAUTH_SIGNUP=trueLike the session key, the client secret goes in the .env file (OAUTH_CLIENT_SECRET=…), not in compose.yml.
The callback URL to declare in your identity provider is https://openwebui.yourdomain.com/oauth/oidc/callback.
Restart the stack after modification:
docker compose up -dTo restrict SSO access to a specific email domain (e.g. @your-company.com), configure the restriction directly in your identity provider, not in Open-WebUI. Keycloak and Authentik both allow domain filtering at the OIDC client level — this is the safest control point, as it also covers the API.
Enable RAG on your documents
Open-WebUI includes a RAG (Retrieval-Augmented Generation) pipeline that allows you to query your local documents in a conversation. Processing happens entirely on your VPS — no document is sent to an external service.
To enable RAG:
1. From the interface, click the paperclip in the input area of a conversation, or use the Documents tab in the side menu.
2. Import a PDF, Markdown, DOCX or TXT file. Open-WebUI chunks it, vectorises it and stores it in its local database.
3. In the conversation, prefix your message with # followed by the document name to inject it as context.
For advanced use (multiple documents, thematic collections), the Workspace → Documents section allows you to organise files into collections and associate them with specific models.
By default, Open-WebUI uses its own lightweight embeddings engine. For better performance on a large corpus, you can configure a dedicated Ollama embeddings model (for example nomic-embed-text) in Administration Panel → Documents → Embeddings model.
Add web search with SearXNG
Web search is not built into Open-WebUI: the interface queries an external engine, then injects the pages it finds into the model's context. SearXNG, a self-hosted metasearch engine, spares you a paid API key: it queries several public engines for you and returns a single list. That is also its weakness, covered in the troubleshooting section below.
Three settings are enough. On the SearXNG side, open settings.yml and add json to the formats list under search, next to html: without it, Open-WebUI gets a 403 error. On the Open-WebUI side, open Administration Panel → Settings → Web Search, choose searxng and enter the query URL, for example http://searxng:8080/search?q=<query> (variable SEARXNG_QUERY_URL). You can also set ENABLE_WEB_SEARCH=true and WEB_SEARCH_ENGINE=searxng in compose.yml. If both services share a Docker network, the service name works as the host and SearXNG's port does not need to be published to the Internet.
One trap remains: three switches must be on at the same time, global web search, the model's "web search" capability and the button in the current conversation. Miss one and you get an answer without any search, often with no visible error.
Open-WebUI, AnythingLLM, LibreChat: which interface to choose
Scroll the table
| Criterion | Open-WebUI | AnythingLLM / LibreChat |
|---|---|---|
| LLM backend | Native Ollama + any OpenAI endpoint | OpenAI, Ollama, Azure, LM Studio |
| User management | Built-in, groups, native OIDC | Built-in (AnythingLLM: isolated workspaces) |
| RAG | Native, no configuration required | Native, configurable (LanceDB, pgvector) |
| GitHub stars | 155,000+ (own licence, protected branding) | 65,000+ (MIT) / 45,000+ (MIT) |
| Primary use case | Team with Ollama already deployed | Advanced multi-source RAG / multi-backend chat |
Troubleshooting: common errors
Connection refused on Open-WebUI startup.
Ollama is not yet ready when Open-WebUI tries to connect. Wait 20 seconds and run docker compose restart open-webui. To avoid this on every restart, add a healthcheck on the Ollama service in compose.yml.
Streaming stops after 60 seconds.
Your reverse proxy applies a default HTTP timeout. Add proxy_read_timeout 300s; in the Nginx location / block (or the equivalent timeout in Traefik). LLMs sometimes take several minutes to generate a long response.
WebSocket connection failed.
Verify that the Upgrade and Connection headers are correctly forwarded by the reverse proxy. Without them, SSE/WebSocket streaming is blocked and responses don't arrive in real time.
SSO authentication returns redirect_uri_mismatch.
The callback URL declared in your identity provider does not match what Open-WebUI sends. It must be exactly https://openwebui.yourdomain.com/oauth/oidc/callback — with the full domain name, no trailing slash.
An SSO user can log in but has no access to any model.DEFAULT_USER_ROLE defaults to pending: every new account, SSO included, waits for an administrator to activate it, and ENABLE_OAUTH_SIGNUP only governs account creation. Change their role to user in Administration Panel → Users, or set DEFAULT_USER_ROLE=user in the environment variables.
Unresponsive screen, crypto.randomUUID is not a function in the browser console.
Open-WebUI is served over HTTP on a non-local domain or address: the browser only provides this function in a secure context (HTTPS or localhost). Finish the reverse proxy's TLS setup before testing the AI features.
Web search returns nothing.
See the dedicated section below: test SearXNG on its own before blaming Open-WebUI.
Troubleshooting: web search returns nothing
Symptom. Web search is enabled, but the conversation shows No results found from web search (a 404 error in Open-WebUI's log), or the model answers without having searched.
What that message says. Open-WebUI did reach SearXNG, sent the query and received an empty list. A public case illustrates it (open-webui issue #32401, opened on 14 October 2026 after an upgrade to 0.12.0): the author suspected the new version, the maintainers first blamed the model, then, with SearXNG's own log in hand, found that DuckDuckGo answered with a CAPTCHA, Brave with "Too many requests" (engine suspended for 3 minutes each time) and Startpage with a redirect to its CAPTCHA. Every engine blocked, so zero results. According to the maintainers, those sites were blocking the IP address regardless of the upgrade. The issue was closed the same day with no fix on the Open-WebUI side, and the author ended up choosing the DDGS provider.
The method to keep: before blaming the version or the model, query SearXNG on its own.
Diagnose an empty web search
Query SearXNG without Open-WebUI
From the VPS, run
curl -s 'http://127.0.0.1:8080/search?q=test&format=json', adjusting host and port to your setup (if SearXNG is only reachable over the Docker network, run the command from a container on that network). Three outcomes: a 403 error meansjsonis missing fromformats; an emptyresultslist means the engines are failing; a filled list means SearXNG works and the problem is on the Open-WebUI or model side (see the tip below).Read SearXNG's log
docker compose logs --tail 200 searxngshows what each engine answered. Look for lines that name an engine (duckduckgo, brave, startpage…) with a CAPTCHA, a refusal for too many requests or a timeout. An engine that comes back on every search with the same error is blocked for your VPS's IP address, which happens more readily to a data-centre address.Enable or replace engines
In
settings.yml, underengines, enable general-purpose engines that are not blocked: Open-WebUI's maintainers mention Google, Bing, Mojeek and Qwant. An entryname: mojeekwithdisabled: falseenables an engine present in the default settings; withuse_default_settings: trueat the top of the file, you only list your differences. Restart withdocker compose restart searxng, then replay step 1 until you get results. Enable several engines: a single active engine quickly falls into the block again.Use a keyed provider if the IP stays blocked
If every engine fails, an API provider sidesteps the problem: Brave Search API, Tavily or Serper are chosen on the same administration screen. For Brave's free tier, set
WEB_SEARCH_CONCURRENT_REQUESTS=1. The DDGS provider, which the issue author settled on, needs no key.
SearXNG returns results, but the assistant never searches? Since version 0.10.0 (late June 2026), native tool calling is the default mode: web search becomes a tool the model must call itself, and an old or small model skips it or writes a malformed call. Pick a recent model that handles tools and check that Function Calling is set to Native in the model's advanced parameters; the maintainers describe Legacy mode as unsupported. If the search succeeds but pages fail to load, look at WEB_SEARCH_TRUST_ENV behind an HTTP proxy, then USER_AGENT.
Track the usage of a team instance
Knowing who consumes what quickly becomes a budget question once developers call the instance through the API. Today, four sources complement each other, each with a blind spot:
The four measurement sources
- The Analytics dashboard (administration settings, Analytics section): messages, input and output tokens, per model and per user, with group and period filters; since 0.12.4, ranking is by tokens. It is computed from the message history stored in the database: whatever is not stored there does not appear.
ENABLE_ADMIN_ANALYTICS=Falsehides it. - The personal view (settings, Usage tab, since 0.11.0 in July 2026): each user sees their own activity, and nothing of anyone else's.
- The audit log: off by default (
AUDIT_LOG_LEVEL=NONE). WithAUDIT_LOG_LEVEL=METADATA, Open-WebUI writesaudit.login its data directory (rotation at 10 MB) for requests authenticated by anAuthorizationheader or a cookie: API calls therefore appear, with the requested model. To also get the tokens of each reply (since 0.12.4), remove/chatfromAUDIT_EXCLUDED_PATHS, which defaults to/chats,/chat,/folders. Avoid theREQUESTandREQUEST_RESPONSElevels, which record the content of conversations, and replay a test call to read the entry produced before building any count on it. - The reverse proxy logs: the simplest angle for volume. With Nginx's combined format,
awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | headranks the most-called paths; add$request_timeto yourlog_formatto spot slow requests. This log sees neither the user nor the tokens, and theAuthorizationheader must never be recorded in it.
What usage tracking does not do yet
The request for tracking that separates the interface from the API and attributes calls to each key is open on the project's repository: open-webui issue #21675, "enh: analytics", created on 20 February 2026 and still open on 7 November 2026, with about a hundred comments. The thread reports that an API user placed in a group does not appear in Analytics, and on 14 October a team whose developers mostly go through the API was still asking for that visibility. No date is announced there: do not plan anything around this feature.
The maintainers answer that a filter, meaning a Python function installed in the interface, can count requests, including API ones; a contributor points out that passthrough routes escape it. They file per-user or per-group caps under rate limiting, outside the Analytics topic. Reading the SQLite database webui.db directly remains possible on a copy, but its schema is not a contract and changes from one version to the next. A contributor has also published a third-party quota plugin: a function runs with the server's privileges, so read its code before enabling it.
Give each developer their own account and their own API key rather than a shared key: without a distinct identity, none of the four sources can attribute usage. If the API becomes the main channel, a gateway in front of Ollama that counts calls at the source (LiteLLM, already in the ServOrbit catalogue, offers virtual keys and spend tracking) is a lead worth testing before you adopt it.
Secure access to the Ollama API
By default, Ollama listens on 0.0.0.0:11434 inside its container. The compose.yml configuration proposed above does not publish this port on the host — only Open-WebUI accesses it via the internal Docker network. This is the correct posture.
If you need to access the Ollama API directly (from an IDE, Jupyter notebook or external application), two options:
1. SSH tunnel: ssh -L 11434:localhost:11434 user@your-vps — the API is accessible locally without public exposure.
2. Reverse proxy with authentication: expose Ollama behind Nginx with auth_basic or a Bearer token, if you have clients that don't support SSH tunnelling.
Never publish port 11434 directly on the public interface without authentication: the Ollama API has no native protection against unauthorised access.
To keep Open-WebUI up to date, change the image from ghcr.io/open-webui/open-webui:main to ghcr.io/open-webui/open-webui:v0.13.0 (or the latest stable tag) in your compose.yml. The :main tag follows continuous development — handy for testing new features, less predictable in production. Check the release notes on GitHub before each update: some versions have introduced database migrations, others change default behaviours (native tool calling in 0.10.0), and the 0.12.0 notes recommend updating production deployments promptly for its security fixes.
Advanced features to explore after deployment
- Pipelines and functions: Open-WebUI allows writing Python functions that intercept the conversation flow — filters, context enrichers, connectors to external APIs.
- Custom models: create pre-configured 'models' (system instructions, temperature, context) and share them with specific user groups.
- Image generation: connect Open-WebUI to a local Stable Diffusion or ComfyUI instance to generate images directly in chat.
- Integration with external tools: via the MCP (Model Context Protocol) protocol, Open-WebUI can call external tools — databases, REST APIs, web search.
Official documentation
For advanced configuration and tool-specific options, refer to the official Open-WebUI documentation. This guide covers basic deployment and the most common configurations — parameters specific to your environment (LDAP integration, pipeline configuration, embeddings tuning) are in the project documentation.