GuidesFiles, photos and homeAI chat with Open WebUI

Your own AI chat with Open WebUI, OpenRouter and rootless Podman

Open WebUI on Debian 13 in rootless Podman behind Caddy, a private ChatGPT-style chat for you and your family or team, with models from OpenRouter, sign-ups closed, and its calls to Hugging Face and GitHub switched off.

Tested on Open WebUI 0.11.4 on Debian 13 (trixie) on a Melonslab server Updated October 2, 2026

Recommended server for this guide

VC-S Micro · 2 vCPU · 8 GB Memory · 250 GB Storage

Month to month, no lock-in 7-day money-back guarantee

€7.99/mo

Deploy now
On this page

What you will set up

Open WebUI is a chat app in the browser, much like ChatGPT, that you run yourself. Chats, uploaded documents and user accounts stay on your server. The answers come from an AI model elsewhere: here from OpenRouter, one API key that reaches hundreds of models from many providers, a few of them free. No model runs on the server itself, so a small server is enough.

Open WebUI is developed by Open WebUI, Inc., a company in San Francisco, USA, founded by Timothy Jaeryang Baek. Its licence, the "Open WebUI License", is the BSD 3-clause licence with one extra clause: you may not remove or change the Open WebUI name and logo, unless your installation has at most 50 users in any 30 days, or you have permission or an enterprise licence from the company. Older code remains under the earlier MIT and BSD licences. OpenRouter is run by OpenRouter, Inc. in New York, USA. Everything you type in a chat goes to OpenRouter and on to the provider of the model you pick. OpenRouter says it does not store prompts unless you opt in, but it keeps metadata such as token counts, and each provider has its own policy on logging and training.

Here Open WebUI runs in rootless Podman under a user of its own called openwebui, behind Caddy from the Podman guide.

Every step below was run on a fresh Melonslab VC-P Alloy (2 vCPU, 8 GB) with Debian 13:

  • The admin account was created over an SSH tunnel before the site was public. Afterwards, sign-ups were closed, and a sign-up attempt from outside was refused.
  • A second user saw only the one model the admin had made public, and chatted with OpenRouter's free models at no cost.
  • A question about an uploaded document was answered from that document, with the document search running on the server.
  • With the settings below, Open WebUI connected only to openrouter.ai. With its defaults it also downloaded files from Hugging Face at every start and asked GitHub for new versions.
  • Logins showed visitors' real IPv4 and IPv6 addresses, chats streamed over a WebSocket through Caddy, and everything came back by itself after a reboot, with users still logged in.

Open WebUI used about 690 MB of memory. Its image takes 4.7 GB of disk.

Before you start

You need:

  • a server set up as in the Podman guide, with Caddy running, and ideally ufw from the security guide;
  • an A record and an AAAA record for chat.example.com pointing at your server;
  • an OpenRouter account and an API key (step 7).

The examples use chat.example.com for Open WebUI and 203.0.113.10 for your server's IPv4 address. Replace them throughout.

1. Create the user

As root:

useradd -m -s /bin/bash openwebui
loginctl enable-linger openwebui
machinectl shell openwebui@

Everything up to step 6 runs as openwebui.

2. Create the secret key

Open WebUI signs its login sessions with a secret key. If you do not give it one, the image makes a new key inside the container, and Quadlet creates the container afresh at every restart, so everyone would be logged out each time. Store a random key as a Podman secret:

openssl rand -base64 32 | tr -d '\n' | podman secret create webui-secret-key -

3. Describe the container

mkdir -p ~/.config/containers/systemd

Create ~/.config/containers/systemd/open-webui.container:

[Unit]
Description=Open WebUI

[Container]
ContainerName=open-webui
Image=ghcr.io/open-webui/open-webui:main
Volume=open-webui:/app/backend/data
# Only Caddy, on this server, can reach Open WebUI: the port is not open to the internet.
PublishPort=127.0.0.1:8103:8080
Secret=webui-secret-key,type=env,target=WEBUI_SECRET_KEY
Environment=WEBUI_URL=https://chat.example.com
Environment=CORS_ALLOW_ORIGIN=https://chat.example.com
# Caddy's connections arrive from the server's own IPv4 address
Environment=FORWARDED_ALLOW_IPS=203.0.113.10
# No local models: the chats go to OpenRouter
Environment=ENABLE_OLLAMA_API=False
Environment=OPENAI_API_BASE_URL=https://openrouter.ai/api/v1
# No downloads from Hugging Face, no update check against GitHub
Environment=OFFLINE_MODE=True
# No buttons that send chats, models and prompts to openwebui.com
Environment=ENABLE_COMMUNITY_SHARING=False
AutoUpdate=registry

[Service]
Restart=always
TimeoutStartSec=300

[Install]
WantedBy=default.target

The main image is the one without a bundled Ollama, which would run models on the server. Everything Open WebUI keeps is in the open-webui volume: a SQLite database with users, chats and settings, uploaded files, and the index of their contents.

What the settings do:

  • WEBUI_URL and CORS_ALLOW_ORIGIN give the public address, used in links and to accept requests only from your own site.
  • FORWARDED_ALLOW_IPS trusts Caddy to pass on the visitor's real address. Inside the container, Caddy's connections appear to come from the server's IPv4 address.
  • OPENAI_API_BASE_URL makes OpenRouter the only model connection. Without it, Open WebUI starts with a connection to OpenAI.
  • OFFLINE_MODE stops two calls that the defaults make. At every start, Open WebUI checks Hugging Face (Hugging Face, Inc., USA) for a newer version of the small model it uses to search documents, and downloaded about 800 MB from it in our test. And it asks GitHub's API for the latest release, to tell the admin about updates. The model needed for document search is already in the image, so documents still work. The setting also stops plugins from installing Python packages.
  • ENABLE_COMMUNITY_SHARING=False removes the Share to Open WebUI Community buttons, which send a chat, a model or a prompt to openwebui.com when clicked.

The image already sets the switches for anonymous usage statistics (SCARF_NO_ANALYTICS, DO_NOT_TRACK, ANONYMIZED_TELEMETRY) to off.

Most of these settings are read only at the very first start, and are then kept in the database, where later changes in this file do not reach them. Write the whole file before you start Open WebUI for the first time; afterwards, change settings in the admin pages instead.

4. Start it

systemctl --user daemon-reload
systemctl --user start open-webui
systemctl --user enable --now podman-auto-update.timer

The first start downloads the 4.7 GB image, which took about two and a half minutes, so start may take a while to return. Then wait until Open WebUI answers:

curl -s http://127.0.0.1:8103/health

It answers {"status":true} after about 45 seconds.

5. Create your admin account over an SSH tunnel

The first account created in Open WebUI becomes its admin. Create it now, while Open WebUI can only be reached from the server itself: in our test, a scanner visited the site within a minute of it going public.

On your own computer, open a tunnel to the server:

ssh -L 8103:127.0.0.1:8103 root@203.0.113.10

While it is open, go to http://localhost:8103 in your browser. Choose Get started, enter your Name, Email and Password, and choose Create Admin Account.

As soon as the admin exists, Open WebUI closes sign-ups by itself. To check, open your profile picture at the bottom left, Admin Panel, Settings, then Authentication: New Sign Ups is off, and Default User Role is pending. Close the tunnel with exit.

6. Put Caddy in front

Go back to root with exit, switch to machinectl shell caddy@, and add this block at the end of ~/Caddyfile:

chat.example.com {
    reverse_proxy 127.0.0.1:8103
}

Restart Caddy with systemctl --user restart caddy. Caddy passes on the WebSocket connection that Open WebUI streams its answers over, with no extra settings.

Check from your own computer that nobody else can sign up:

curl -s -X POST https://chat.example.com/api/v1/auths/signup \
  -H 'Content-Type: application/json' \
  -d '{"name": "test", "email": "test@example.com", "password": "Test-12345678"}'

The answer is {"detail":"You do not have permission to access this resource. Please contact your administrator for assistance."}.

7. Connect OpenRouter

Create an API key in your account at openrouter.ai, and give it a credit limit. The key in our test had a limit of 0 and used only free models, at no cost.

In Open WebUI at https://chat.example.com, open Admin Panel, Settings, Connections. The connection https://openrouter.ai/api/v1 is already there. Choose the gear icon next to it:

  • Paste the key into API Key.
  • Open Advanced, type openrouter/free under Model IDs, and choose the + next to it. Without this, all of OpenRouter's models are listed, more than 450 in our test, paid ones included. openrouter/free sends each request to one of OpenRouter's free models.
  • Choose Save.

Open WebUI keeps the key in its database, in plain text: the config table of webui.db in the open-webui volume. Anyone with the backup from step 11, or root on the server, can read it, so keep the credit limit low.

Free models are slower, rate-limited, and in our test allowed 50 requests a day. Each provider has its own policy on what it keeps and whether it trains on your prompts. In your OpenRouter account's privacy settings, you can block providers that may train on prompts, with separate settings for free and paid models.

8. Choose which models users can use

Models in Open WebUI are private to the admin until you share them, so a new user sees no models at all. Open Admin Panel, Settings, Models, choose the pencil next to openrouter/free, then Access, change Private to Public, close the dialog, and choose Save & Update.

Public lets every user use the model. To give a model only to some people, leave it Private and add them, or a group from Admin Panel, Users, Groups, with Add Access.

9. Chat

Choose New Chat, make sure openrouter/free is selected at the top, and ask something. The answer streams in after a few seconds.

To ask about a document, drag it into the message box. Open WebUI splits it up and indexes it on the server, and sends only the parts that match your question to the model. In our test, it found a code word in a short text file.

Each message you send results in more than one request to OpenRouter: in our test, one message used four of the 50 free requests, because Open WebUI also asks the model for a chat title, tags and suggested follow-up questions. To save requests, or money with paid models, turn off Title Generation, Follow Up Generation and Tags Generation under Admin Panel, Settings, Interface.

10. Add users

Under Admin Panel, Users, choose Add User, pick the Role user, and enter a Name, an Email and a Password. Give the person the password, and ask them to change it under Settings, Account.

Alternatively, turn on New Sign Ups under Authentication for a while. New accounts are then pending: they cannot chat until you change their role to user in Admin Panel, Users. Turn sign-ups off again afterwards.

If you later use paid models:

  • The credit limit on the OpenRouter key caps what all users together can spend. Raise it in small steps.
  • Add each paid model under Model IDs in step 7, and share it only with the users or groups who may use it, as in step 8.

11. Back up

As openwebui:

mkdir -p ~/backup
systemctl --user stop open-webui
podman volume export open-webui --output ~/backup/open-webui.tar
systemctl --user start open-webui
podman secret inspect --showsecret --format '{{.SecretData}}' webui-secret-key > ~/backup/webui-secret-key
chmod 600 ~/backup/*

The volume holds the database with users, chats, settings and the OpenRouter key, the uploaded files and their index. It was 266 MB in our test, including the 120 MB search model. Copy ~/backup to another machine, and keep it private.

To restore, create the secret from the saved file with podman secret create webui-secret-key ~/backup/webui-secret-key, then podman volume create open-webui and podman volume import open-webui ~/backup/open-webui.tar before the first start. We restored a backup into a new volume, and logged in with the same account.

12. Keep it up to date

The timer from step 4 checks for a new image every day, and restarts Open WebUI when there is one. The main tag follows Open WebUI's releases. podman auto-update --dry-run shows whether an update is waiting. A new version may change the database when it starts, so keep a recent backup from step 11.

Troubleshooting

A setting in the container file has no effect. Most settings are read only at the first start, and later the database wins. Change them in the admin pages. In our test, ENABLE_COMMUNITY_SHARING=False added after the first start left community sharing on.

A user sees no models. The models are still private. Share them as in step 8.

All of OpenRouter's models are listed, paid ones included. Model IDs in the connection from step 7 is empty: add openrouter/free, choose the +, then Save.

Everyone has the server's own IP address in Open WebUI's log. That is expected for visits through the SSH tunnel. For visits through Caddy, check that FORWARDED_ALLOW_IPS is the server's IPv4 address.

Run it on your own server

VC-S Micro

€7.99/mo

vCPU
2
Memory
8 GB
Storage
250 GB
Transfer
10 TB
Standard
HDD · RAID 10
  • Full root access
  • Native /64 IPv6
  • RAID-protected storage
  • Malmö, Sweden
  • Month to month, no lock-in
  • 7-day money-back guarantee
All guides