SSD Nodes Learn 🎉 VPS from $4.99/mo
Guides Matt ConnorBy Matt Connor · Updated 2026-08-07

Open WebUI alternatives for a VPS

Open WebUI, LibreChat, Hollama and OrionChat compared on a VPS with a public IP: RAM left for the model, logins, remote Ollama, and upkeep.

Which Open WebUI alternative belongs on a VPS

Open WebUI alternatives are almost always compared on a laptop, where RAM is cheap and nothing listens on a public address. A VPS changes both facts, and that changes the ranking. Open WebUI stays the right default the moment a second person logs in, because it ships real user accounts and an admin panel. The lighter projects win when the interface is competing with the model for the last gigabyte of RAM. The price of that win is authentication: they have none.

Everything below comes from each project's own documentation, read in August 2026. The four axes are the ones that only appear once the box is reachable from the internet.

Four axes that only matter on a public IP

  • Memory next to the model. The model server is the expensive process on the box. Every megabyte the interface holds is a megabyte the model cannot have.
  • Authentication. Some of these projects have user accounts and roles. Others assume they are the only thing running on your laptop, and they have no login at all.
  • Remote inference. A UI that can only reach 127.0.0.1:11434 forces the model onto the same box as the interface.
  • Upkeep. One container with a SQLite file is a different job from six containers with MongoDB and a vector database behind them.

How much RAM does the model leave for the interface

The interface is not the biggest thing on the box. The model is. Published download sizes give you the floor, because the weights have to be resident while the model answers, and real memory use is higher than the download once the context cache is allocated.

ChartPublished download size of common Ollama models, August 2026
The data behind this chart
[
  {
    "label": "llama3.2:3b",
    "download_gb": "2.0"
  },
  {
    "label": "qwen3:4b",
    "download_gb": "2.5"
  },
  {
    "label": "gemma3:4b",
    "download_gb": "3.3"
  },
  {
    "label": "qwen3:8b",
    "download_gb": "5.2"
  }
]

Those are the figures the Ollama library pages printed in August 2026. They are published sizes, not measurements. On a 4 GB VPS, qwen3:4b at 2.5 GB leaves under 1.5 GB for the operating system and everything else, and the context cache eats into that as a conversation grows. qwen3:8b at 5.2 GB does not fit on that box at all. This is the situation the laptop roundups never cover, and it is where a chat interface holding a few hundred megabytes decides whether the model runs. If you are sizing a box for something well above these tags, the arithmetic for a 27B model on a CPU-only VPS shows how quickly the interface stops being the number that decides anything.

Measure rather than trust any number in a roundup, including this one. Run docker stats --no-stream an hour into real use, not one minute after the container starts, because the memory that matters is allocated on first use.

Open WebUI: still the default for more than one user

Open WebUI runs from one image and keeps its data in one volume.

docker run -d -p 127.0.0.1:3000:8080 -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main

The command in the project README publishes -p 3000:8080, which listens on every interface. The 127.0.0.1: prefix keeps it on loopback. On a VPS that prefix matters more than anything else on the line, because Docker writes its own iptables rules and a published port ignores your ufw deny rules.

Reach the page through a tunnel or a proxy, both described below, then create the first account. That account becomes the administrator. Later signups are created with the role pending, the documented default of DEFAULT_USER_ROLE, so a stranger who reaches the page still cannot use your model until an admin approves them.

Open WebUI costs more memory than the projects below because it does more, and its own performance page names the parts that cost it. The default embedding engine loads a sentence-transformers model inside the container, documented at around 500 MB per worker process. Setting RAG_EMBEDDING_ENGINE=ollama hands that job to the model server you already run. AUDIO_STT_ENGINE=webapi avoids loading a local speech-to-text model. On SQLite with DATABASE_POOL_SIZE unset, the pool falls back to a large internal size and each connection grows its own page cache and memory map, so on a small box set DATABASE_POOL_SIZE=8 and DATABASE_SQLITE_PRAGMA_MMAP_SIZE=0. ENABLE_AUTOCOMPLETE_GENERATION=False stops the interface asking the model for a completion while a user is still typing.

LibreChat: multi-user, with a stack behind it

git clone https://github.com/danny-avila/LibreChat.git
cd LibreChat
cp .env.example .env
docker compose up -d

The interface answers on port 3080. LibreChat is the one to look at when you need an identity system rather than a login box: it documents LDAP and OAuth2 logins, and it bundles an admin panel for users and roles. That capability arrives with a stack.

ChartContainers a default install adds, not counting the model server
The data behind this chart
[
  {
    "label": "OrionChat",
    "containers": 0,
    "notes": "static files, served by a web server you already run"
  },
  {
    "label": "Hollama",
    "containers": 1,
    "notes": "one container serving a browser app"
  },
  {
    "label": "Open WebUI",
    "containers": 1,
    "notes": "application and SQLite in one image"
  },
  {
    "label": "LibreChat",
    "containers": 6,
    "notes": "api, admin panel, MongoDB, Meilisearch, pgvector, RAG API"
  }
]

The default compose file starts 6 services: api, admin panel, MongoDB, Meilisearch, pgvector, RAG API. None of them is the model. MongoDB and pgvector each want memory of their own, and on a 4 GB box that is memory the model wanted.

Upgrades are a git operation, which is the part people get wrong.

docker compose down
git pull
docker compose pull
docker compose up -d

git pull stops with a conflict if you edited the tracked docker-compose.yml, and then the upgrade is half applied. Put your changes in docker-compose.override.yml, which the project provides for this, and keep secrets in .env. Both files are untracked, so git pull leaves them alone.

Point LibreChat at your own model server with a custom endpoint in librechat.yaml.

endpoints:
  custom:
    - name: "Ollama"
      apiKey: "ollama"
      baseURL: "http://model-host:11434/v1/"
      models:
        default: ["llama3.2"]
        fetch: true
      titleConvo: true
      titleModel: "current_model"
      modelDisplayLabel: "Ollama"

Replace model-host with the address of the box running Ollama. The apiKey field has to be present even though Ollama ignores its value, so a placeholder is fine. If LibreChat runs in Docker and Ollama runs on the same machine, localhost inside the container means the container itself, so use host.docker.internal there instead.

Hollama and OrionChat: the browser does the work

Hollama serves a browser application from one small container. Chats live in your browser's storage, not on the server.

docker run -d --restart unless-stopped -p 127.0.0.1:4173:4173 --name hollama ghcr.io/fmaclen/hollama:latest

The README version of this command uses --rm, which deletes the container when it stops, so the interface never comes back after a reboot. Behind a reverse proxy, add -e VITE_ALLOWED_HOSTS='chat.example.com', because the image allows the host localhost only and answers a request for any other hostname with a blocked-host error instead of the app.

OrionChat goes further and has no server component at all. Clone the repository and serve the folder with the web server you already run, or open index.html from disk. API keys are stored in the browser's localStorage, chat history stays in the browser, and the app deletes the oldest chats once the count passes 512.

Neither project has a login, because neither has a server that could check one. On a laptop that is fine. On a VPS it means the page must never be published on 0.0.0.0, and it means something easier to miss: the browser calls the model, not the server.

That one fact decides where these two are usable. Your browser has to reach Ollama directly, so Ollama has to listen on more than loopback, and Ollama has no authentication of any kind. Two browser rules follow from it. A page served over HTTPS cannot call a plain HTTP endpoint, and the console prints Mixed Content: The page at 'https://chat.example.com/' was loaded over HTTPS, but requested an insecure resource 'http://203.0.113.10:11434/api/tags'. This request has been blocked. A call to any other origin is refused with has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource until you allow that origin.

Ollama's documented way to change either setting is a systemd override.

sudo systemctl edit ollama.service
[Service]
Environment="OLLAMA_HOST=0.0.0.0:11434"
Environment="OLLAMA_ORIGINS=https://chat.example.com"
sudo systemctl daemon-reload
sudo systemctl restart ollama
sudo ss -lntp | grep 11434

ss should now print 0.0.0.0:11434 where it printed 127.0.0.1:11434 before. Only make that change when a firewall or an authenticating proxy already controls who can reach the port, because an open 11434 is an open model server and mass scanners reach a new public port quickly. The SSH tunnel below avoids the whole question: the page then runs on a localhost origin, which Ollama permits by default, and the port never leaves the box.

Can each one use a remote Ollama or vLLM endpoint

Open WebUI can, and the connection is made server side. OLLAMA_BASE_URL=http://model-host:11434 points it at Ollama. For vLLM or any other OpenAI-compatible server, set OPENAI_API_BASE_URL=http://model-host:8000/v1 with a non-empty OPENAI_API_KEY, and keep the /v1 suffix, which is required. OPENAI_API_BASE_URLS accepts several backends separated by semicolons.

LibreChat can, through the baseURL of the custom endpoint shown above. That request also leaves the server, so no browser rule applies.

Hollama and OrionChat can point at any endpoint you type into their settings, but the request leaves your browser. Everything in the section above applies to them and to nothing else here.

Splitting the interface from the model is the most useful thing a remote endpoint buys you. Put the interface on a small box and the model where the memory is. That is also the point to decide whether Ollama or vLLM should serve the requests, because the two behave very differently once several people talk to the model at once. If the model server does not exist yet, start by running Ollama on a VPS, and on a CPU-only box read how Ollama compares with llama.cpp before you pick a runner.

Never publish a chat UI with no login on 0.0.0.0

Open WebUI's hardening page says the project is "built for private, trusted networks, similar to other self-hosted infrastructure like databases, container registries, and CI servers", and it tells you to place it behind a VPN or behind a reverse proxy with authentication. A project with no login at all deserves at least the same treatment.

Check what is listening before you trust any of it.

sudo ss -lntp | grep -E ':(3000|3080|4173|11434)'

A line reading 127.0.0.1:3000 is what you want. A line reading 0.0.0.0:3000 means your chat interface is on the public internet. From your own machine, curl -sI http://YOUR.VPS.IP:3000 answering HTTP/1.1 200 OK says the same thing more bluntly.

Turning Open WebUI's login off with WEBUI_AUTH=False is a single-user setting for a machine nobody else can reach. It also refuses to apply to an installation that already has accounts, with the message You can't turn off authentication because there are existing users.

Pattern one: bind to loopback and reach it over SSH. Publish every port on 127.0.0.1, then forward what you need: ssh -N -L 3000:127.0.0.1:3000 you@vps.example.com, and open http://localhost:3000 on your laptop. Nothing is published, so nothing can be scanned. For Hollama or OrionChat, forward the model port in the same command with -L 11434:127.0.0.1:11434 and leave Ollama on loopback. The pattern is only as strong as your SSH setup, so pair it with key-only SSH and a hardened sshd.

Pattern two: a reverse proxy that authenticates before the app sees the request. Keep the app on loopback, let the proxy own port 443, and put single sign-on in front. Traefik driven by Docker Compose labels with Authentik as the identity provider gives every app on the box one login and one certificate. With Open WebUI behind TLS (transport layer security), set WEBUI_SESSION_COOKIE_SECURE=true and WEBUI_SESSION_COOKIE_SAME_SITE=strict. Shorten JWT_EXPIRES_IN from its four-week default too, because Open WebUI documents that without Redis a sign-out does not invalidate the token: it stays usable until it expires on its own.

Pattern two does not rescue the browser-only projects. A proxy in front of the page does not protect the model endpoint, and a fetch from that page to a different hostname does not carry your session cookie, so the authenticating proxy in front of Ollama answers with a redirect to a login form and the chat fails. Either route the model endpoint under the same hostname as the page, or use pattern one.

Which one to pick

If anyone other than you will use it, run Open WebUI. It has real accounts, new users land in an approval queue, and its maintainers publish hardening guidance you can follow. If you need LDAP or an admin panel, run LibreChat, and confirm with docker stats that its six services plus your model actually fit before you depend on it. If it is one person on a small box where the model has already claimed most of the RAM, serve Hollama or OrionChat over an SSH tunnel and let the browser hold the state. The wrong answer on a VPS is any of them published on 0.0.0.0 with no login in front.

FAQ

Is Open WebUI safe to expose directly on a public IP?

Its own hardening page describes it as software for private, trusted networks, in the same category as a database or a CI server. It does have real accounts, and the first account becomes an administrator while later ones stay pending until approved, so it is far safer than a UI with no login. Still put it behind a reverse proxy with TLS and, where you can, single sign-on. Publish the container port as 127.0.0.1:3000:8080 so Docker's own iptables rules cannot open it to the internet behind your back.

Which Open WebUI alternative uses the least RAM on a VPS?

The browser-based ones, Hollama and OrionChat, because the application runs on the client. The server only sends static files, and OrionChat needs no application container at all. Open WebUI keeps a Python process, a database and, by default, a local embedding model in memory, documented at around 500 MB per worker for the embedding model alone. Confirm the numbers on your own box with docker stats --no-stream, because they move with the features you turn on.

Can these chat UIs use an Ollama server on another host?

Open WebUI and LibreChat can, and their server makes the connection, so no browser rule applies. Set OLLAMA_BASE_URL for Open WebUI, or baseURL in a custom endpoint for LibreChat. For vLLM or another OpenAI-compatible server, use OPENAI_API_BASE_URL with the /v1 suffix and a non-empty API key. Hollama and OrionChat can also point anywhere, but the request comes from your browser, so the endpoint must be reachable from your browser as well.

Why can my browser chat UI not reach Ollama?

Two causes cover nearly every case. Ollama binds 127.0.0.1:11434 by default, so a browser on another machine never reaches it until OLLAMA_HOST changes. And Ollama accepts cross-origin requests from localhost only, so a page served from your own domain is refused with No 'Access-Control-Allow-Origin' header is present on the requested resource until that origin is listed in OLLAMA_ORIGINS. If the page is HTTPS and the endpoint is HTTP, the browser blocks the call as mixed content before Ollama ever sees it. Set both variables in a systemctl edit ollama.service override, or forward the port over SSH and the problem disappears.