OpenWebUI — Installation¶
Primary audience: TAPPaaS admin.
Prerequisites¶
- LiteLLM must be deployed and accessible before installing OpenWebUI (
litellm:modelsdependency). LiteLLM must also have at least one model registered — OpenWebUI is wired to it automatically, but an empty LiteLLM means an empty model list (see Troubleshooting). - Identity (Authentik) must be deployed (
identity:identitydependency) — OpenWebUI signs users in via SSO. -
The environment owner must exist in people-manager with a
primaryEmail, because that identity becomes the OpenWebUI admin. Resolution isenvironments/<env>.json .ownerOrg-> people org.owner-> user.primaryEmail. Check with:people-manager org show "$(jq -r .ownerOrg /home/tappaas/config/environments/
.json)" people-manager user show -
Verify
openwebui.jsonmatches your environment (node, storage, zone).
To deviate from the defaults in
./openwebui.json(target node, storage, zone/VLAN, sizing), copy the json to/home/tappaas/configand edit it before installing.
Fields can also be overridden with flags at install time, e.g. install-module.sh openwebui --node tappaas1 --zone0 srvDev --vmid 399, or a named variant config (--variant staging).
Install¶
install-module.sh openwebui
Duration: ~10–20 minutes on first run (NixOS rebuild + container pull ~1 GB).
What the install wires up automatically¶
No manual configuration is required after installing. Three things that used to be hand-configured are now part of the converge, and are re-applied by every module-manager reconcile openwebui --apply:
| Integration | What happens | Where it lands |
|---|---|---|
| LiteLLM | litellm:models provisions a per-consumer virtual key and writes /etc/secrets/litellm-svckey.env. openwebui-integrations.service translates it into OPENAI_API_KEY / OPENAI_API_BASE_URL. | /etc/secrets/openwebui-integrations.env |
| SSO (Authentik) | identity:identity creates the OIDC application and writes /etc/secrets/openwebui-oidc.env. The same service translates it into OAUTH_CLIENT_ID / OAUTH_CLIENT_SECRET / OPENID_PROVIDER_URL. | same file |
| Admin account | update.sh resolves the environment owner and pushes the identity; openwebui-seed-admin.service creates that account before anyone can log in, so the admin is deterministic rather than "whoever signs up first". | /etc/secrets/openwebui-owner.env |
Notes worth knowing:
- OpenWebUI makes the first account an admin. Seeding exists so that account is the environment owner. It is skipped entirely once any account exists, so it can never take over an instance already in use.
- The seeded account is created through OpenWebUI's own signup API with a random, discarded password.
OAUTH_MERGE_ACCOUNTS_BY_EMAIL=truemeans the owner's first SSO login adopts that account rather than creating a second, non-admin one. - Credential rotation is handled:
identity:identityrestartsopenwebui-integrations.service, which regenerates the settings and restarts the container only when the content actually changed.
Post-install¶
First login:
- Open OpenWebUI at
http://<vmname>.<zone>.internal:8080(or itsproxyDomainif published). - Sign in with SSO as the environment owner. You land in the pre-seeded admin account.
- Start a conversation and pick a model — the LiteLLM connection is already configured under Settings -> Connections; do not add it by hand.
For upgrades of an existing install see UPGRADE.md. To restore application data from backups see RESTORE.md.
Optional: publish to the internet¶
OpenWebUI ships internal-only: openwebui.json declares
"network:proxy": { "proxyAllowedZones": ["home"] }
so the reverse proxy accepts clients from the home zone and refuses everything else — including the internet. That is the intended default for an LLM chat UI; only widen it deliberately.
A request from a zone that is not allowed gets HTTP 403 from Caddy. That is worth recognising: a 403 means the request reached the proxy and was refused there, so the firewall path is fine and only the access list needs changing. A missing firewall rule times out instead.
To publish it, add the literal internet zone (which means "no restriction"), then converge:
# deployed config, NOT the module source — this is a per-site decision
cd /home/tappaas/config
cp openwebui.json openwebui.json.bak
tmp=$(mktemp)
jq '.config["network:proxy"].proxyAllowedZones = ["internet"]' openwebui.json > "$tmp"
mv "$tmp" openwebui.json && chmod 600 openwebui.json
module-manager reconcile openwebui --apply
Verify:
curl -o /dev/null -w '%{http_code}\n' https://<proxyDomain>/ # expect 200
# SSO redirect must carry the PUBLIC callback URL
curl -o /dev/null -w '%{redirect_url}\n' https://<proxyDomain>/oauth/oidc/login
The second check matters: the OIDC application's redirect_uri is derived from the module's domain, so it must point at the public host you are now serving. If it does not, re-run the converge so identity:identity re-applies.
Two caveats:
- A 502 immediately after the converge is usually transient. The container is restarted to pick up new settings; Caddy returns 502 while it comes back. Check
curl http://127.0.0.1:8080/on the VM — if that answers 200, just retry. - This lives in the deployed config only.
install-module.sh openwebui --reinstallre-copies the module source and reverts to["home"]. Re-apply afterwards, or change the authoredopenwebui.jsonif this site always wants it published — but note that changes the shipped default for every deployment of this module, so prefer the deployed-config route.
To narrow it again, set the zones back (e.g. ["home"]) and reconcile.
Verification¶
test-module.sh openwebui
| Check | Expected |
|---|---|
| SSH connectivity | PASS |
| OpenWebUI container | running |
| HTTP endpoint on port 8080 | responding (200) |
| PostgreSQL | accepting connections |
| Redis | responding to PING |
litellm:models | VK provisioned, key file present, VK resolves >0 models |
Spot-check the automated wiring directly (secrets redacted):
ssh tappaas@<vmname>.<zone>.internal \
"sudo sed -E 's/(KEY|SECRET)=.*/\1=<redacted>/' /etc/secrets/openwebui-integrations.env"
Expect OPENAI_API_BASE_URL, OPENAI_API_KEY, and the OAUTH_* / OPENID_PROVIDER_URL block. Confirm the admin is the environment owner:
ssh tappaas@<vmname>.<zone>.internal \
"sudo -u postgres psql -d openwebui -tAc 'SELECT email, role FROM \"user\"'"
Troubleshooting¶
These checks cover deployment failures only. For operational issues after a successful install see ADMIN.md.
install-module.sh exits with dependency error
A required service is not installed. Check which dependsOn entry is unmet:
rules-manager list-installed --no-ssl-verify
Install the missing module first, then retry.
Container fails to start on first boot
DNS or image pull failed during NixOS activation. Check from inside the VM:
ssh tappaas@openwebui.srvWork.internal "sudo journalctl -u openwebui-wrapper -n 30"
Common fix: wait 2–3 minutes for NixOS first-boot to complete, then run test-module.sh openwebui.
Test shows LiteLLM unreachable
Firewall pinhole not applied. Re-run install:
install-module.sh openwebui --force
Model list is empty (but sign-in works)
OpenWebUI is wired to LiteLLM correctly; LiteLLM has no models to serve. This is a LiteLLM configuration matter, not an OpenWebUI one. Confirm on the LiteLLM VM:
MK=$(sudo grep '^LITELLM_MASTER_KEY=' /etc/secrets/litellm.env | cut -d= -f2-)
curl -sS -H "Authorization: Bearer $MK" http://127.0.0.1:4000/v1/models
An empty data array means no models are registered. module-manager test openwebui reports this as VK key resolves 0 models. Register models on LiteLLM, then re-run module-manager reconcile openwebui --apply.
No SSO button on the login page
The OIDC half of the settings file is missing — identity:identity has not run or failed. Check for the OAUTH_* keys:
ssh tappaas@<vmname>.<zone>.internal "sudo grep -c OAUTH_ /etc/secrets/openwebui-integrations.env"
If zero, re-apply: module-manager reconcile openwebui --apply.
The admin account is not the environment owner
Seeding only runs on an instance with zero accounts — by design, so it cannot displace real users. If someone signed up before the seed ran, they hold admin. Promote the owner from within OpenWebUI (Admin Panel -> Users), or, on a throwaway instance, delete the accounts and re-run module-manager reconcile openwebui --apply.
Check what the seeder decided:
ssh tappaas@<vmname>.<zone>.internal "journalctl -u openwebui-seed-admin -n 5"
no owner email recorded yet means the owner could not be resolved on the TAPPaaS side — see Prerequisites step 3.