How to Install Open WebUI on Ubuntu 24.04 VPS: Self-Hosted ChatGPT-Style Frontend for Ollama
Open WebUI gives you a polished, ChatGPT-like browser interface for any local language model you run on your server. Pair it with Ollama, vLLM, or llama.cpp and you get conversations with memory, document upload for RAG, web search, image generation, role-based access control, and a plugin system (pipelines) -- all on hardware you own. This guide walks through a production install on Ubuntu 24.04 using Docker, connecting to a local Ollama backend, and fronting the whole stack with Nginx and Let's Encrypt TLS.
Skip the manual setup? Our CloudCore Professional VPS gives you 6 vCPU, 12 GB RAM, and 100 GB NVMe for EUR 19.99/month -- enough to run Ollama, Open WebUI, and a 7B-9B parameter model comfortably.
Table of Contents
What is Open WebUI?
Open WebUI (formerly Ollama WebUI) is an open-source, self-hosted web interface for large language models. It presents a chat experience that closely mirrors ChatGPT -- streaming responses, conversation history, markdown and LaTeX rendering, code highlighting, and multi-modal inputs -- but every request runs against a model backend you control. The project ships as a single Docker image, includes built-in vector storage for retrieval-augmented generation, and supports any inference engine that speaks the Ollama API or the OpenAI Chat Completions schema.
Under the hood Open WebUI is a FastAPI backend with a SvelteKit frontend, SQLite (or PostgreSQL) for user and chat storage, and ChromaDB for RAG embeddings. It supports user accounts with role-based permissions, workspaces for isolating conversations by team, document collections that become searchable knowledge bases, prompt libraries and model presets, web search integration with SearxNG, Tavily, Brave, or Google PSE, image generation via Automatic1111, ComfyUI, or DALL-E, voice input and text-to-speech, and a pipelines framework for injecting custom logic like guardrails, rate limiting, function calling, or logging.
It is the de-facto ChatGPT replacement for self-hosters. Teams use it as an internal AI assistant that never leaks proprietary data, individual developers use it as a privacy-respecting personal chatbot, and agencies deploy it to clients as a branded AI portal. If you are already running Ollama on Ubuntu, adding Open WebUI is the natural next step.
Why Self-Host Instead of Paying for ChatGPT Plus?
ChatGPT Plus at USD 20/month is convenient, but the tradeoffs matter more than the price:
- Your data stays on your server. Prompts, uploaded documents, generated images, and chat history never leave the VPS. For companies handling customer data, legal documents, medical records, or proprietary code, this is not a nice-to-have; it is a compliance requirement.
- No per-message caps, no throttling. ChatGPT Plus enforces a 3-hour message window on GPT-4-class models. Open WebUI backed by your own GPU or CPU has no such ceiling -- you are limited only by your hardware.
- Model freedom. Use Llama 3.1, Gemma 2, Mistral, DeepSeek, Qwen, or any GGUF from Hugging Face. Swap models per conversation. Mix a small fast model for routing with a larger model for generation. This is impossible on ChatGPT.
- Flat, predictable cost. A CloudCore Professional VPS is EUR 19.99/month regardless of whether your team sends 100 messages or 100,000. Compared to per-token OpenAI API billing, break-even arrives quickly for active teams.
- Custom system prompts and tools per user. Give engineering a code-focused assistant, give support a ticket-summarization prompt, give finance a spreadsheet helper -- all from the same UI with RBAC enforcing who sees what.
- RAG over your own documents. Upload PDFs, Markdown, and CSVs. Open WebUI chunks, embeds, and indexes them locally. Queries retrieve relevant passages and feed them to the model. Your knowledge base never touches a third-party API.
- Integrations you actually own. Web search through SearxNG (self-hosted), image generation through local Stable Diffusion, speech-to-text through local Whisper. The whole stack is portable.
Cost Snapshot
| Plan | Monthly Cost | Message Limit | Data Exposure | Model Choice |
|---|---|---|---|---|
| ChatGPT Plus | USD 20 | ~80 GPT-4o / 3 hr | Sent to OpenAI | GPT-4o, o1-mini |
| OpenAI API (pay-as-you-go) | USD 50-400+ at scale | Token-based | Sent to OpenAI | OpenAI catalogue |
| Open WebUI + Ollama on CloudCore Professional | EUR 19.99 | Unlimited | Stays on your VPS | Any open model |
Prerequisites
Before starting, you need:
- A VPS running Ubuntu 24.04 LTS with root or sudo access.
- At least 4 GB RAM for Open WebUI itself. If you are also running Ollama on the same box, plan 8-12 GB minimum to hold a 7B-9B model in memory.
- 20 GB free disk for the container image, SQLite database, RAG embeddings, and uploaded documents.
- A domain name pointed at your server's IP (required for TLS in Step 7).
- An inference backend. This guide assumes Ollama; see How to Install Ollama on Ubuntu. Alternatives: vLLM for GPU throughput, llama.cpp for low-level control.
Recommended Plan: CloudCore Professional>
The CloudCore Professional plan is the sweet spot for a combined Ollama + Open WebUI stack:>
- 6 vCPU cores
- 12 GB RAM
- 100 GB NVMe SSD
- Unmetered bandwidth
- EUR 19.99 / month>
Twelve gigabytes is enough headroom for a 7B-9B model loaded full-time, the UI container, and a handful of concurrent users. For 70B models or heavy team usage, step up to a GPU plan.
Connect via SSH:
ssh root@your-server-ipStep 1: Prepare the Server and Install Docker
Update the package index and install upgrades:
sudo apt update && sudo apt upgrade -yInstall Docker Engine from the official Docker APT repository. The version shipped in Ubuntu's default repo is usually outdated:
sudo apt install -y ca-certificates curl gnupg sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \ sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod a+r /etc/apt/keyrings/docker.gpgecho "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \ https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Verify Docker:
sudo docker run --rm hello-worldExpected output ends with:
Hello from Docker!
This message shows that your installation appears to be working correctly.Enable Docker to start on boot:
sudo systemctl enable --now dockerAdd your user to the docker group so you can run commands without sudo:
sudo usermod -aG docker $USER
newgrp dockerStep 2: Pull and Run Open WebUI with Docker
Open WebUI publishes official images at ghcr.io/open-webui/open-webui. The :main tag tracks the latest stable release, :dev tracks the development branch, and there are tagged variants bundled with Ollama (:main-ollama), CUDA (:cuda), and embedded models.
Pull the base image:
docker pull ghcr.io/open-webui/open-webui:mainExpected output (abbreviated):
main: Pulling from open-webui/open-webui
a480a496ba95: Pull complete
b7c9218f0b57: Pull complete
...
Status: Downloaded newer image for ghcr.io/open-webui/open-webui:mainCreate a persistent volume for Open WebUI's data (SQLite DB, uploaded files, RAG vectors, user avatars):
docker volume create open-webuiGenerate a strong secret key for session signing -- do not skip this step, and do not commit the key to version control:
openssl rand -hex 32Copy the output. You will paste it into the WEBUI_SECRET_KEY environment variable below.
Run the container. This command assumes Ollama is running on the host at 127.0.0.1:11434 and uses --add-host=host.docker.internal:host-gateway so the container can reach it:
docker run -d \
--name open-webui \
--restart unless-stopped \
-p 127.0.0.1:3000:8080 \
-e OLLAMA_BASE_URL=http://host.docker.internal:11434 \
-e WEBUI_SECRET_KEY="paste-your-openssl-output-here" \
-e ENABLE_SIGNUP=true \
-e DEFAULT_USER_ROLE=pending \
-v open-webui:/app/backend/data \
--add-host=host.docker.internal:host-gateway \
ghcr.io/open-webui/open-webui:mainFlag-by-flag:
-p 127.0.0.1:3000:8080-- binds the UI only to localhost. Nginx (Step 7) terminates TLS and proxies to this port. If you are running on a private network and plan to expose directly, change to-p 3000:8080.-e OLLAMA_BASE_URL-- where Open WebUI looks for the Ollama API.host.docker.internalresolves to the Docker host thanks to--add-host.-e WEBUI_SECRET_KEY-- used to sign session cookies and API tokens. Must remain stable across restarts or users will be logged out.-e ENABLE_SIGNUP=true-- allows new user registration. Flip tofalseafter your team is onboarded to lock the system down.-e DEFAULT_USER_ROLE=pending-- new users land in a pending state and cannot chat until an admin approves them. Other options:user,admin.-v open-webui:/app/backend/data-- persists the database, vectors, and uploads across container upgrades.
docker ps --filter name=open-webui
docker logs --tail 30 open-webuiYou should see lines ending with:
INFO: Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit)Step 3: Connect Open WebUI to Ollama
If Ollama is installed on the same VPS (see How to Install Ollama on Ubuntu), make sure it listens on all interfaces so the container can reach it. Edit or create the systemd override:
sudo mkdir -p /etc/systemd/system/ollama.service.d sudo tee /etc/systemd/system/ollama.service.d/override.conf > /dev/null <<'EOF' [Service] Environment="OLLAMA_HOST=0.0.0.0:11434" EOF
sudo systemctl daemon-reload sudo systemctl restart ollama
Confirm Ollama is reachable from the Docker host network:
curl http://host.docker.internal:11434 || curl http://172.17.0.1:11434Both should return Ollama is running. If neither works, add a UFW allow rule scoped to the Docker bridge:
sudo ufw allow in on docker0 to any port 11434Adding Multiple Backends
Open WebUI can federate across multiple Ollama servers and any OpenAI-compatible API simultaneously. Set both variables when running the container:
-e OLLAMA_BASE_URL=http://host.docker.internal:11434 \
-e OPENAI_API_BASE_URL=https://api.openai.com/v1 \
-e OPENAI_API_KEY=sk-your-key-here \You can also configure backends after login under Admin Panel -> Settings -> Connections. Multi-backend setups are useful for running small local models for bulk work while keeping a hosted model available for high-quality one-off queries.
Alternative Backends
Open WebUI works with any OpenAI-compatible endpoint. Common pairings:
- vLLM -- Point
OPENAI_API_BASE_URLathttp://vllm-host:8000/v1. See How to Install vLLM on Ubuntu. - llama.cpp server -- Start
llama-serverwith--host 0.0.0.0and point Open WebUI athttp://host:8080/v1. See How to Install llama.cpp on Ubuntu. - LiteLLM proxy -- Route to Anthropic, Google, Cohere, or any provider through a unified OpenAI-compatible gateway.
Step 4: Create the First Admin Account
Open a browser on your workstation and tunnel to port 3000:
ssh -L 3000:127.0.0.1:3000 root@your-server-ipThen visit http://localhost:3000 in your browser. If you have already set up Nginx (Step 7), go directly to https://yourdomain.com.
You will see Open WebUI's sign-up screen. The first account created is automatically promoted to administrator. There is no default password or seed user -- whoever registers first owns the instance. Register immediately to prevent a stranger from claiming admin.
Fill in a strong name, email, and password. After signing up you will land in the chat UI. The top-left model selector should already list any models you pulled with ollama pull. If it is empty, recheck the Ollama connection in Step 3.
Send a test message like What is a VPS? to confirm streaming works. The first response takes a few seconds while the model loads into RAM; subsequent messages stream immediately.
Now click your avatar -> Admin Panel to enter the admin console.
Step 5: Manage Models, Users, and RBAC
Managing Models
Navigate to Admin Panel -> Settings -> Models. You will see three tabs:
- Pull a model from Ollama.com -- Type a name like
llama3.1:8b,mistral:7b-instruct, orgemma2:9band click the download icon. Open WebUI forwards the request to Ollama, which downloads and registers the model. - Create a Modelfile -- Build a preset that combines a base model with a system prompt, temperature, context window, and optional knowledge base. Users see these presets as distinct chatbots in the model selector.
- Delete models -- Reclaim disk by removing unused pulls.
SupportBot with your product docs attached, CodeHelper with low temperature and a code-focused system prompt, ResearchAssistant with web search enabled.Managing Users
Under Admin Panel -> Users you can approve pending signups, change roles, suspend accounts, reset passwords, and delete users. If you set ENABLE_SIGNUP=false after onboarding, you create accounts manually from this screen.
Roles in Open WebUI:
- Admin -- full access; can manage other users, models, and system settings.
- User -- can chat, use tools, upload documents to personal collections.
- Pending -- created but not activated; cannot log in.
RBAC with Groups and Permissions
Open WebUI ships a granular permissions model. Go to Admin Panel -> Settings -> Users -> User Permissions to toggle per-role capabilities:
- Chat deletion, editing, sharing
- File uploads, voice input, image generation
- Web search, direct model access
- Workspace creation
FinanceBot Modelfile tied to your accounting SOPs, while engineering sees code-focused models with access to your engineering wiki.Step 6: Enable RAG, Web Search, and Image Generation
RAG with Document Upload
Retrieval-augmented generation is built in. Go to Workspace -> Knowledge and click Create Knowledge Base. Give it a name, then drag-and-drop PDFs, DOCX, Markdown, CSV, or plain text files. Open WebUI chunks each document, generates embeddings via its configured embedding model, and stores vectors in ChromaDB inside the volume you created in Step 2.
Configure embedding behavior under Admin Panel -> Settings -> Documents:
- Embedding Model Engine -- default uses a bundled Sentence Transformers model. Switch to Ollama (
nomic-embed-text) for faster GPU-accelerated embeddings, or OpenAI (text-embedding-3-small) for highest quality. - Chunk Size and Chunk Overlap -- default 1000 / 200 works for most prose. Drop to 500 / 100 for code or tables.
- Top K -- how many chunks to retrieve per query. Raise to 8-10 for long documents, keep at 3-5 for snappy responses.
# hashtag in the prompt box and select the collection. The model receives retrieved chunks as context before generating.You can also attach documents to a Modelfile so every conversation with that preset automatically has access -- ideal for customer-support bots.
Web Search
Go to Admin Panel -> Settings -> Web Search and enable it. Supported providers:
- SearxNG (recommended, fully self-hosted) -- set the URL to your local SearxNG instance
- Tavily -- developer-friendly AI search with an API key
- Brave Search API
- Google PSE (Programmable Search Engine)
- DuckDuckGo -- no key needed but rate-limited
Image Generation
Under Admin Panel -> Settings -> Images, enable an image backend:
- Automatic1111 -- point at your Stable Diffusion WebUI endpoint (
http://host:7860) - ComfyUI -- point at ComfyUI's API (
http://host:8188) - OpenAI DALL-E -- provide your API key
Step 7: Expose Open WebUI with Nginx and TLS
Open WebUI should never be exposed on plain HTTP. Install Nginx and Certbot:
sudo apt install -y nginx certbot python3-certbot-nginxPoint your domain (ai.yourdomain.com) at the server's public IP with an A record, then create an Nginx site:
sudo tee /etc/nginx/sites-available/open-webui > /dev/null <<'EOF' server { listen 80; server_name ai.yourdomain.com; return 301 https://$host$request_uri; }server { listen 443 ssl http2; server_name ai.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/ai.yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/ai.yourdomain.com/privkey.pem;
# Security headers add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Content-Type-Options nosniff; add_header X-Frame-Options SAMEORIGIN; add_header Referrer-Policy strict-origin-when-cross-origin;
# Large uploads for RAG documents client_max_body_size 100m;
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;
# Streaming responses and long-running requests proxy_buffering off; proxy_read_timeout 600s; proxy_send_timeout 600s;
# WebSocket upgrade for live features proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } } EOF
sudo ln -s /etc/nginx/sites-available/open-webui /etc/nginx/sites-enabled/ sudo nginx -t
Obtain a certificate and reload:
sudo certbot --nginx -d ai.yourdomain.com --redirect --agree-tos -m [email protected] -n
sudo systemctl reload nginxUpdate the Open WebUI container with a matching public URL so generated links (password reset emails, shared chats) resolve correctly:
docker stop open-webui
docker rm open-webui
docker run -d \
--name open-webui \
--restart unless-stopped \
-p 127.0.0.1:3000:8080 \
-e OLLAMA_BASE_URL=http://host.docker.internal:11434 \
-e WEBUI_SECRET_KEY="your-secret" \
-e WEBUI_URL=https://ai.yourdomain.com \
-e ENABLE_SIGNUP=false \
-v open-webui:/app/backend/data \
--add-host=host.docker.internal:host-gateway \
ghcr.io/open-webui/open-webui:mainVisit https://ai.yourdomain.com and log in with the admin account you created earlier.
Step 8: Add Pipelines for Custom Logic
Pipelines are Open WebUI's plugin framework. A pipeline is a Python class that intercepts prompts and responses -- perfect for rate limiting, PII redaction, usage logging, tool calling, or routing between models.
Run the pipelines container alongside Open WebUI:
docker run -d \
--name pipelines \
--restart unless-stopped \
-p 127.0.0.1:9099:9099 \
-v pipelines:/app/pipelines \
ghcr.io/open-webui/pipelines:mainIn Open WebUI, go to Admin Panel -> Settings -> Connections and add a new OpenAI API connection:
- URL:
http://host.docker.internal:9099 - API key:
0p3n-w3bu!(default; change in the pipelines container)
- Rate limit filter -- caps per-user requests per minute
- Langfuse logger -- ships every prompt/response to Langfuse for evaluation
- Cloudflare content filter -- blocks prompts matching a blocklist
- Function calling pipeline -- executes Python functions the model decides to call
- RAG pipeline with custom retrievers -- replaces the built-in ChromaDB with Qdrant, Weaviate, or Pinecone
Backup, Updates, and Maintenance
Backup
Everything lives in the open-webui Docker volume. Snapshot it:
docker run --rm \
-v open-webui:/data \
-v $(pwd):/backup \
alpine tar czf /backup/open-webui-$(date +%F).tar.gz -C /data .Store backups off-site (restic to S3, Backblaze, or a second VPS). Restore by extracting the tarball into a fresh volume before starting the container.
Updates
Pull the latest image, recreate the container, and keep the volume intact:
docker pull ghcr.io/open-webui/open-webui:main docker stop open-webui docker rm open-webui
re-run your docker run command from Step 7
Schema migrations run automatically on first start after an upgrade. Read the release notes before upgrading across major versions.
Monitor Resource Usage
docker stats open-webui --no-streamIf memory climbs steadily with long-running chats, restart the container weekly via a cron job:
0 4 0 /usr/bin/docker restart open-webuiTroubleshooting
| Problem | Cause | Fix |
|---|---|---|
| Model selector is empty | Container cannot reach Ollama | Verify curl http://host.docker.internal:11434 from inside container: docker exec open-webui curl -s http://host.docker.internal:11434. Check OLLAMA_HOST=0.0.0.0 in Ollama override. |
| Streaming responses hang halfway | Nginx buffering enabled or timeout too short | Confirm proxy_buffering off and proxy_read_timeout 600s in Nginx config. Reload: sudo systemctl reload nginx. |
| Login loops / "Invalid token" | WEBUI_SECRET_KEY changed between restarts | Set a stable WEBUI_SECRET_KEY env var. Never omit it -- the container generates a random key each boot if unset. |
| Uploaded PDF never appears in RAG | Embedding model download failed or OOM during chunking | Check docker logs open-webui for embedding errors. Switch embedding engine to Ollama with nomic-embed-text for lower memory. |
| WebSocket errors in browser console | Nginx missing upgrade headers | Ensure the Upgrade and Connection headers are set in the location / block. |
| 502 Bad Gateway from Nginx | Container not running or port mismatch | docker ps to verify container is up. Confirm -p 127.0.0.1:3000:8080 matches proxy_pass http://127.0.0.1:3000. |
| First admin was not created | Signup disabled before first user | Stop container, set ENABLE_SIGNUP=true, restart, create the admin, then set back to false. |
| "Disk full" errors during document upload | RAG embeddings filled the volume | Inspect the volume size: docker system df -v. Migrate the volume to a larger disk or prune unused knowledge bases. |
Viewing Logs
docker logs -f open-webuiStream live logs to debug streaming, authentication, or upload problems.
FAQ
Does Open WebUI work without Ollama?
Yes. Any OpenAI-compatible endpoint works -- vLLM, llama.cpp's llama-server, LocalAI, LiteLLM proxy, or even the real OpenAI API. Set OPENAI_API_BASE_URL and OPENAI_API_KEY instead of (or alongside) OLLAMA_BASE_URL.
Can multiple users share one installation?
Yes, that is the intended deployment mode. Create accounts via signup (then disable signup) or manually from the admin panel. Each user has private chat history, personal knowledge bases, and whatever models / tools their role permits. Organizations typically run one Open WebUI per team or per tenant.
How do I back up chat history?
Chats are stored in webui.db (SQLite) inside the open-webui volume. Tar the volume as shown in the Backup section; that single file restores all users, chats, knowledge bases, and settings. For enterprise deployments, configure Open WebUI to use PostgreSQL via DATABASE_URL and back up with pg_dump.
Does it support voice input and TTS?
Yes. Under Admin Panel -> Settings -> Audio you can enable speech-to-text backed by local Whisper or OpenAI, and text-to-speech via the browser's native voices, ElevenLabs, or a local TTS server. Users then get microphone input and spoken responses.
Is there an iOS or Android app?
Open WebUI is a responsive web app and installs as a PWA on iOS and Android -- visit your domain on mobile, tap "Add to Home Screen," and it behaves like a native app. There is no separate native app, and for self-hosted deployments the PWA is usually preferable because you keep full control of the domain and TLS.
How does this compare to LibreChat?
LibreChat is the closest alternative. Both are mature, self-hosted ChatGPT replacements with multi-backend support, RAG, and team features. Open WebUI leans more toward a Ollama-native experience with deep Modelfile integration and a simpler deployment (one container). LibreChat has stronger multi-agent and plugin ecosystems and richer OpenAI API parity. Either is a solid pick; pick Open WebUI if Ollama is your primary backend and you want the fastest possible setup.
Can I white-label Open WebUI?
Yes. Under Admin Panel -> Settings -> Interface you can set a custom app name, logo, and favicon. More extensive white-labelling (colors, fonts, landing page copy) is possible by mounting a custom theme into /app/backend/data/user_custom_css and overriding frontend assets.
Next Steps
You now have a production-grade Open WebUI install with RAG, web search, image generation, and TLS. Where to go from here:
- Harden the host -- Install fail2ban and CrowdSec to block brute-force attempts on the login endpoint.
- Scale the backend -- Replace Ollama with vLLM for GPU-accelerated throughput at 5-20x the tokens-per-second on the same hardware.
- Run tighter models on CPU -- llama.cpp gives you quantization options (Q2_K through Q8_0) and more aggressive CPU tuning than Ollama exposes.
- Add workflow automation -- Connect Open WebUI's OpenAI-compatible endpoint to n8n, Zapier, or a custom app to run LLM calls in pipelines.
- Document ingestion at scale -- For large document corpora, pair Open WebUI with a dedicated vector DB (Qdrant, Weaviate) via a custom pipeline, and use a larger embedding model like
bge-large-enormxbai-embed-large. - Review the upstream docs -- The Open WebUI documentation is thorough and frequently updated with new integrations.
Want a pre-built AI stack?>
Skip the hour of setup. Our CloudCore Professional VPS at EUR 19.99/month includes everything you need -- 6 vCPU, 12 GB RAM, 100 GB NVMe -- to run Ollama, Open WebUI, and a 7B-9B model comfortably. Deploy in minutes and start chatting with your own private AI.