Post

Open WebUI

Open WebUI

Open WebUI

Self-hosted chat interface for a remote Ollama instance, with retrieval-augmented web search. Runs in the default namespace of the k3s cluster, fronted by Traefik.

Deployment

ItemValue
Imageghcr.io/open-webui/open-webui:v0.11.4
Namespacedefault
Replicas1 (Recreate strategy)
Node placementx86 k3s LXC nodes (nodeSelector kubernetes.io/arch: amd64 + picluster/lxc: "true"); follows its local-zfs volume
ServiceClusterIP, port 8080
IngressTraefik IngressRoute — chat.prod-k3s.homelab.example, TLS via the shared local-example-com-tls wildcard cert
Storageopen-webui-data-zfs PVC, 5Gi, local-zfs storage class, mounted at /app/backend/data
Auto-reloadreloader.stakater.com/auto: "true"

Configuration

Open WebUI points at an external Ollama server rather than running its own model runtime:

Env varValue
OLLAMA_BASE_URLhttps://ollama.intel.homelab.example
ENABLE_RAG_WEB_SEARCHTrue
RAG_WEB_SEARCH_ENGINEsearxng
RAG_WEB_SEARCH_RESULT_COUNT3
RAG_WEB_SEARCH_CONCURRENT_REQUESTS10
WEBUI_SECRET_KEYSourced from the open-webui-secrets Secret
TZAmerica/New_York

Storage

The volume holds real, growing user data (chat history, accounts, uploaded documents, webui.db). It is a node-local local-zfs volume: a directory on that node’s ZFS-backed volume (a zvol on the TrueNAS NVMe pool, attached to the k3s LXC node), so the pod is scheduled where its volume is; the node’s volume is snapshotted and replicated off-site nightly.

WEBUI_SECRET_KEY gotcha

If WEBUI_SECRET_KEY isn’t set explicitly, Open WebUI writes an auto-generated key to /app/backend/.webui_secret_key — outside the PVC-backed DATA_DIR. Every pod restart would then regenerate the key and invalidate all logged-in sessions. This is worked around by setting WEBUI_SECRET_KEY explicitly via the open-webui-secrets Secret; rotating that secret logs every user out.

Readiness/liveness probes

Cold start downloads the RAG embedding model (sentence-transformers/all-MiniLM-L6-v2) from Hugging Face before the server starts listening — this took roughly 10 minutes on first boot, hence generous probe settings (initialDelaySeconds: 30, failureThreshold: 60 on both probes against GET /health). Without this, Traefik routes to the pod before it’s ready and every request 502s until the download finishes.

Migrated from Docker Compose

Originally ran as a Docker container on a separate Intel NUC host (chat.intel.homelab.example). Converted to this cluster’s Kubernetes pattern (Deployment + ClusterIP Service + PVC + Traefik IngressRoute) with the hostname updated to chat.prod-k3s.homelab.example to match every other app already migrated. PUID/PGID and host-path /etc/localtime mounts were dropped (not applicable to this image or a multi-node cluster) in favor of a TZ env var.

This post is licensed under CC BY 4.0 by the author.