Open WebUI Self-Host on a VPS: Docker, Nginx & HTTPS

Self-host Open WebUI on a VPS with Docker, Ollama, Nginx and free HTTPS: a private ChatGPT-style interface for your team, locked down and ready to update.

Open WebUI is the easiest way to self-host a ChatGPT-style interface for yourself or your team. It gives you chat history, multiple users, model switching, document uploads with built-in RAG, and an admin panel, and it connects to Ollama or any OpenAI-compatible API.

I set this up for a client who wanted staff to use AI on internal documents without anything leaving their own server. In this guide I deploy Open WebUI and Ollama on an Ubuntu VPS with Docker Compose, put Nginx in front as a reverse proxy with WebSocket support, add a free Let's Encrypt certificate, and lock it down so strangers cannot sign up.

Commands reflect Open WebUI as of October 2026. Note that Open WebUI uses its own license (based on BSD-3 with a branding clause) rather than a plain MIT license; read it if you plan to rebrand it for clients.

Prerequisites

  • An Ubuntu 22.04 or 24.04 VPS. For CPU-only Ollama with small models, 4 vCPU and 16 GB RAM is a sensible minimum; a GPU server is much faster.
  • A domain or subdomain with an A record pointing at the server, e.g. chat.example.com
  • SSH access with a sudo user
  • Optional: an OpenAI-compatible API key if you want to use hosted models alongside local ones

Step 1: Prepare the server and install Docker

sudo apt update && sudo apt upgrade -y

# Firewall: only SSH and web traffic
sudo ufw allow OpenSSH
sudo ufw allow 80
sudo ufw allow 443
sudo ufw enable

# Docker Engine + Compose plugin (official convenience script)
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER
newgrp docker
docker compose version

Step 2: Docker Compose for Open WebUI and Ollama

I run both containers on a private Docker network. Neither port is published to the public interface: Open WebUI is bound to 127.0.0.1:3000 so only Nginx can reach it, and Ollama is not published at all. Open WebUI talks to Ollama by its service name.

WEBUI_SECRET_KEY signs login sessions; set it to a long random value so users stay logged in across container restarts.

mkdir -p ~/openwebui && cd ~/openwebui
openssl rand -hex 32   # copy the output into .env

# .env
WEBUI_SECRET_KEY=paste-the-random-value-here

# docker-compose.yml
services:
  ollama:
    image: ollama/ollama:latest
    restart: unless-stopped
    volumes:
      - ollama:/root/.ollama
    # For an NVIDIA GPU (after installing nvidia-container-toolkit):
    # deploy:
    #   resources:
    #     reservations:
    #       devices:
    #         - driver: nvidia
    #           count: all
    #           capabilities: [gpu]

  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    restart: unless-stopped
    depends_on:
      - ollama
    ports:
      - "127.0.0.1:3000:8080"
    environment:
      - OLLAMA_BASE_URL=http://ollama:11434
      - WEBUI_SECRET_KEY=${WEBUI_SECRET_KEY}
      - WEBUI_URL=https://chat.example.com
    volumes:
      - open-webui:/app/backend/data

volumes:
  ollama:
  open-webui:

# Start and pull a model
docker compose up -d
docker compose exec ollama ollama pull qwen3:8b
docker compose logs -f open-webui

Step 3: Nginx reverse proxy with WebSocket support

Open WebUI uses WebSockets for live updates and streams long responses, so the proxy must pass Upgrade headers, allow long timeouts and disable buffering. Without these, chats hang or arrive all at once. I also raise client_max_body_size so users can upload documents.

sudo apt install -y nginx

# /etc/nginx/sites-available/openwebui
server {
    listen 80;
    server_name chat.example.com;

    client_max_body_size 100M;

    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-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_buffering off;
        proxy_read_timeout 600s;
        proxy_send_timeout 600s;
    }
}

sudo ln -s /etc/nginx/sites-available/openwebui /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Step 4: Free HTTPS with Let's Encrypt

Certbot's Nginx plugin obtains the certificate, edits the server block to listen on 443 and sets up the HTTP to HTTPS redirect. Renewal runs automatically from a systemd timer.

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d chat.example.com --redirect -m you@example.com --agree-tos

# Confirm automatic renewal works
sudo certbot renew --dry-run

Step 5: Create the admin and lock down sign-ups

Open https://chat.example.com immediately after deploying. The first account created becomes the administrator, so do this before anyone else can find the URL.

Then, in Admin Panel > Settings, disable new sign-ups or set the default role for new users to pending, so you approve each account. You can also set ENABLE_SIGNUP=false in the environment. Afterwards, add users manually from the admin panel.

# docker-compose.yml, under open-webui.environment
      - ENABLE_SIGNUP=false

docker compose up -d   # recreate the container with the new setting

Step 6: Updates and backups

All chats, users and uploaded files live in the open-webui volume, and models live in the ollama volume. Back up the first one regularly; models can always be pulled again.

# Update to the latest images
cd ~/openwebui
docker compose pull
docker compose up -d
docker image prune -f

# Back up Open WebUI data to a tarball
docker run --rm -v openwebui_open-webui:/data -v "$PWD":/backup alpine \
  tar czf /backup/openwebui-$(date +%F).tar.gz -C /data .

Common errors

  • Ollama: connection failed in the UI: OLLAMA_BASE_URL is wrong. Inside Compose use http://ollama:11434; if Ollama runs on the host instead, use http://host.docker.internal:11434 with extra_hosts host-gateway and make Ollama listen on an address the container can reach.
  • Chat responses hang or appear only at the end: Nginx is buffering or dropping WebSockets. Check the Upgrade/Connection headers and proxy_buffering off.
  • 502 Bad Gateway: the container is not running or still starting. Check docker compose ps and docker compose logs open-webui.
  • Everyone is logged out after a restart: WEBUI_SECRET_KEY was not set, so a new one was generated. Set it in .env.
  • 413 Request Entity Too Large on uploads: increase client_max_body_size in Nginx.
  • Very slow answers: the model is too big for a CPU-only VPS. Use a smaller model or a GPU server, or connect a hosted OpenAI-compatible API in Admin Settings > Connections.

Security best practices

  • Never publish Ollama's port 11434 to the internet; it has no authentication.
  • Bind Open WebUI to 127.0.0.1 and expose it only through Nginx with HTTPS.
  • Disable open sign-up and review users and their roles regularly.
  • Keep Docker images updated; Open WebUI releases frequently and includes security fixes.
  • Be careful with features that execute code, such as tools and functions; only install ones you have reviewed, and only let admins add them.
  • For extra protection, put the site behind your company SSO, a VPN, or Nginx IP allow-lists.
  • Back up the data volume and test a restore at least once.

Conclusion

With Docker Compose, Nginx and Let's Encrypt, Open WebUI gives you a private, self-hosted ChatGPT alternative in under an hour. Your team gets a familiar chat interface, you choose which local or hosted models they can use, and conversations stay on a server you control. Lock down sign-ups on day one, keep the images updated, and back up the data volume.

Frequently asked questions

Is Open WebUI free?

Yes, Open WebUI is free to self-host. It uses its own license based on BSD-3 with a branding clause, so read it if you plan to remove or replace the Open WebUI branding.

Can Open WebUI run without a GPU?

Yes. Open WebUI itself needs little power. Ollama can run small models on CPU, or you can connect Open WebUI to a hosted OpenAI-compatible API instead.

How do I disable sign-ups in Open WebUI?

Create the admin account first, then turn off new sign-ups in Admin Panel > Settings, or set the ENABLE_SIGNUP=false environment variable and restart the container.

Why are Open WebUI responses not streaming behind Nginx?

Nginx needs WebSocket headers (Upgrade and Connection), proxy_http_version 1.1, proxy_buffering off and long read timeouts for Open WebUI to stream correctly.

Can Open WebUI use OpenAI or other APIs as well as Ollama?

Yes. Add any OpenAI-compatible endpoint under Admin Settings > Connections, and users can switch between local and hosted models.