
You don’t need a hosted AI chat SaaS to get a clean, ChatGPT-style UI for your own models. If you already have a VPS, you can self-host Open WebUI and connect it to Ollama. Put the stack behind Nginx, add HTTPS, and apply a few simple guardrails. Then it’s ready for daily use.
This walkthrough uses Ubuntu (Debian is nearly identical). The goal is a setup you can run day to day. By the end you’ll have:
- Ollama running locally (models stay on your server)
- Open WebUI running in Docker and talking to Ollama over localhost
- Nginx reverse proxy with Let’s Encrypt TLS
- Basic access control options (Nginx auth, IP allowlist, and rate limiting)
- A repeatable way to update and troubleshoot
What you’ll deploy (and why this layout works)
The most dependable layout is: Open WebUI (Docker) → Ollama (host), with Nginx in front.
Nginx terminates TLS and is your only public entry point on ports 80/443. Ollama stays bound to localhost. Its API never faces the internet.
Open WebUI stores users, chats, and settings in a Docker volume. Ollama stores models under /var/lib/ollama (default).
If you later migrate to a larger server, those are the directories that matter.
Prerequisites and resource sizing for a VPS
Pick a VPS plan based on the models you want to run. On CPU-only plans, small quantized models are usable.
Latency climbs quickly once more than one person is chatting.
- OS: Ubuntu 22.04/24.04 LTS (or Debian 12)
- CPU-only baseline: 4 vCPU, 8–16 GB RAM for small/medium quantized models
- Comfortable CPU-only: 8 vCPU, 16–32 GB RAM (better throughput, fewer timeouts)
- Disk: NVMe recommended; keep at least 30–80 GB free for models
- Public DNS: a domain/subdomain like
ai.example.com
Rule of thumb: quantization lowers RAM/VRAM requirements. You may give up a bit of quality.
On CPU-only servers, that tradeoff usually makes sense. It helps keep response times reasonable.
If you want to sanity-check your Ollama + Nginx setup first, HostMyCode has a dedicated guide: Install Ollama on Ubuntu VPS With Nginx and TLS.
For this tutorial, you can run everything on a single HostMyCode VPS.
If you’d rather avoid OS patching, firewall tweaks, and service maintenance, managed VPS hosting keeps the ops load lighter.
Step 1: Create DNS and set basic firewall rules
Create an A/AAAA record for your subdomain pointing to the VPS IP. Then expose only what you need.
On Ubuntu with UFW:
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status
Leave Ollama off the public network. Don’t open port 11434 to the internet.
If you want a clean baseline UFW profile for web servers, see: Set Up UFW Firewall on Ubuntu for a Web Server.
Step 2: Install Ollama and bind it to localhost only
Install Ollama using the official installer. It also creates a system service.
Next, force it to bind to localhost. This keeps the API unreachable from outside the VPS.
curl -fsSL https://ollama.com/install.sh | sh
sudo systemctl enable --now ollama
systemctl status ollama --no-pager
Create a systemd override so it listens only on 127.0.0.1:
sudo systemctl edit ollama
Paste:
[Service]
Environment="OLLAMA_HOST=127.0.0.1:11434"
Apply the change:
sudo systemctl daemon-reload
sudo systemctl restart ollama
Quick verification (this should work on the VPS):
curl -s http://127.0.0.1:11434/api/tags | head
From another machine on the internet, it should fail. That failure is the point.
Step 3: Pull a model in Ollama (pick one that fits your RAM)
On a CPU-only VPS, start small. You can add bigger models later.
If a model doesn’t fit, it will crawl or get OOM-killed.
Pull a model (example):
ollama pull llama3
List what you have:
ollama list
Quick test chat from the shell:
ollama run llama3
The first response can take a while on CPU-only. After the model loads and caches, follow-up prompts usually feel much better.
Step 4: Install Docker Engine (for Open WebUI)
Open WebUI is easiest to run as a container. On Ubuntu, install Docker from the official repository.
This avoids stale distro packages.
sudo apt-get update
sudo apt-get 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.gpg
echo \
"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-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Confirm the install:
docker --version
docker compose version
Step 5: Run Open WebUI in Docker and connect it to Ollama
Create a working directory:
sudo mkdir -p /opt/open-webui
cd /opt/open-webui
Create a docker-compose.yml that:
- Runs Open WebUI on
127.0.0.1:3000(not public) - Stores data in a named Docker volume
- Points Open WebUI at your local Ollama endpoint
sudo tee /opt/open-webui/docker-compose.yml > /dev/null <<'YAML'
services:
open-webui:
image: ghcr.io/open-webui/open-webui:main
container_name: open-webui
restart: unless-stopped
environment:
- OLLAMA_BASE_URL=http://host.docker.internal:11434
- WEBUI_HOST=0.0.0.0
- WEBUI_PORT=8080
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
- open-webui:/app/backend/data
ports:
- "127.0.0.1:3000:8080"
volumes:
open-webui:
YAML
Start it:
sudo docker compose up -d
sudo docker ps
Check logs if something looks off:
sudo docker logs --tail=100 open-webui
Test locally from the VPS:
curl -I http://127.0.0.1:3000/
If you see HTTP headers, the service is reachable on localhost. Next you’ll publish it through Nginx with HTTPS.
Step 6: Put Nginx in front (reverse proxy with sane defaults)
Install Nginx:
sudo apt-get update
sudo apt-get install -y nginx
Create an Nginx site for ai.example.com (replace with your domain):
sudo tee /etc/nginx/sites-available/open-webui > /dev/null <<'NGINX'
server {
listen 80;
server_name ai.example.com;
# Basic hardening
server_tokens off;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
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 support (useful for some realtime UIs)
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
}
NGINX
Enable the site and validate the config:
sudo ln -s /etc/nginx/sites-available/open-webui /etc/nginx/sites-enabled/open-webui
sudo nginx -t
sudo systemctl reload nginx
Step 7: Add HTTPS with Let’s Encrypt (Certbot)
Install Certbot for Nginx:
sudo apt-get install -y certbot python3-certbot-nginx
Issue a certificate (replace domain and email):
sudo certbot --nginx -d ai.example.com -m you@ai.example.com --agree-tos --no-eff-email
Certbot will update Nginx for TLS and add an HTTP→HTTPS redirect.
Confirm auto-renewal:
sudo systemctl status certbot.timer --no-pager
sudo certbot renew --dry-run
For a deeper TLS troubleshooting checklist (renewals, wrong chain, mixed content), keep this nearby: TLS setup guide tutorial (2026): Configure HTTPS with Let’s Encrypt on a VPS.
Step 8: Add basic access controls (pick at least one)
Open WebUI includes its own auth features. Still treat the endpoint like an admin console.
Add at least one extra layer at Nginx.
Option A: HTTP Basic Auth at Nginx (fast and effective)
Install the password utility and create a password file:
sudo apt-get install -y apache2-utils
sudo htpasswd -c /etc/nginx/.htpasswd youruser
Edit your Nginx server block and add auth inside location / (or at server level):
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
Reload Nginx:
sudo nginx -t && sudo systemctl reload nginx
Option B: IP allowlist (best if you only need office/home access)
Add this inside location /:
allow 203.0.113.10;
allow 198.51.100.0/24;
deny all;
It’s blunt, but reliable. If your IP changes often, route access through a VPN.
If you want a straightforward admin VPN for your VPS in 2026, set up WireGuard and use the UI through the tunnel: Set Up WireGuard VPN on Ubuntu VPS for Admin Access.
Option C: Nginx rate limiting (reduce brute-force and bot pressure)
Even with auth, rate limiting cuts noise. It also helps prevent accidental load spikes.
Add this to /etc/nginx/nginx.conf inside the http { } block:
limit_req_zone $binary_remote_addr zone=webui_rate:10m rate=5r/s;
Then add this inside your location / block:
limit_req zone=webui_rate burst=20 nodelay;
Reload Nginx:
sudo nginx -t && sudo systemctl reload nginx
If you want a more tuned setup (separate zones, better bot handling), see: Nginx Rate Limiting Tutorial (2026).
Step 9: Operational checks (don’t skip these)
Once the UI is live, take two minutes to confirm the basics.
These checks catch most early failures.
- Open WebUI reachable via HTTPS: load
https://ai.example.com - Ollama not public: confirm only localhost listens on 11434
sudo ss -lntp | grep -E '(:11434|:3000|:80|:443)'
- Disk growth: models add up quickly
df -h
sudo du -sh /var/lib/ollama 2>/dev/null || true
sudo docker system df
- Memory pressure: if the kernel OOM-kills ollama, you’ll see it in logs
sudo journalctl -u ollama --since "1 hour ago" --no-pager
dmesg -T | tail -n 80
Updates: how to patch without surprises
You’re maintaining two components: Ollama as a systemd service, and Open WebUI as a Docker container.
Keep updates routine. Plan a rollback path in case something breaks.
Update Open WebUI
cd /opt/open-webui
sudo docker compose pull
sudo docker compose up -d
sudo docker image prune -f
Update Ollama
How you update depends on how you installed it.
If you used the official installer, re-running it typically updates the binary:
curl -fsSL https://ollama.com/install.sh | sh
sudo systemctl restart ollama
After updating, run a quick prompt in the UI. Then watch logs for a minute.
Honest limitations (so you don’t over-promise internally)
- CPU-only inference is slow under concurrency. Two or three users chatting at once can feel sluggish on 4 vCPU.
- RAM is your hard ceiling. If the model doesn’t fit comfortably, you’ll hit swapping or OOM kills.
- Model quality varies more than UI quality. Open WebUI will feel polished, but output quality is model-dependent.
- Security is your job. Treat the endpoint like an internal tool, not a public toy.
If you consistently hit resource limits, move up to a larger VPS or a dedicated machine. That keeps inference from fighting everything else for CPU and RAM.
For higher-usage private chat, a larger HostMyCode VPS plan is usually the cleanest next step. If you’d rather hand off patch windows, monitoring, and break/fix work, managed VPS hosting is a better fit.
Common troubleshooting (quick fixes that save time)
Open WebUI loads but shows no models
This usually means the container can’t reach Ollama.
- Confirm Ollama responds locally:
curl -s http://127.0.0.1:11434/api/tags
- Confirm the container can reach the host gateway:
sudo docker exec -it open-webui sh -lc "wget -qO- http://host.docker.internal:11434/api/tags | head"
If that fails, re-check the extra_hosts entry in Compose. Also confirm Docker is running.
Nginx returns 502 Bad Gateway
This means Nginx can’t reach Open WebUI on 127.0.0.1:3000.
curl -I http://127.0.0.1:3000/
sudo docker ps
sudo docker logs --tail=200 open-webui
If the container keeps restarting, disk pressure or a messy container state are common causes.
A pull + restart fixes many cases:
cd /opt/open-webui
sudo docker compose pull
sudo docker compose up -d
The server becomes unresponsive during prompts
Look for swapping and iowait. On smaller VPS plans, model load can push the system into a bad state.
free -h
vmstat 1 10
top
If swap usage keeps climbing, use a smaller model or add RAM. If iowait is high, NVMe storage makes model loads and image pulls less painful.
Want private AI chat that you control end to end? Run Open WebUI + Ollama on a VPS you manage. Start with a right-sized HostMyCode VPS, and switch to managed VPS hosting if you’d rather offload routine ops and hardening.
FAQ: Self-hosting Open WebUI + Ollama
Should I expose the Ollama API to the internet?
No. Keep Ollama bound to localhost. Only expose Open WebUI through Nginx with HTTPS and access controls.
Public LLM endpoints attract abuse.
Can I run this on a small 2 vCPU / 4 GB VPS?
You can install it, but it won’t be pleasant beyond very small models.
Expect slow responses and memory pressure. 4 vCPU and 8–16 GB RAM is a more realistic starting point.
Do I need Docker for Open WebUI?
It’s the cleanest path for upgrades and rollbacks.
You can run it without Docker, but containerizing keeps dependencies isolated. It also reduces upgrade friction.
What’s the safest way to access it without opening it publicly?
Use an IP allowlist or access it over a WireGuard VPN. That keeps the UI off the public internet while still being convenient.
Summary: a private ChatGPT-like UI on your own VPS
You now have Open WebUI running as a private web app, backed by local Ollama inference. Nginx sits in front with HTTPS.
It’s a solid baseline for internal support tools, dev assistants, or a “chat with your models” box that lives on infrastructure you control.
If you expect steady usage or you want predictable performance, start with more RAM on your HostMyCode VPS plan. Or choose managed VPS hosting if you want tighter maintenance without babysitting the stack.