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
| Item | Value |
|---|---|
| Image | ghcr.io/open-webui/open-webui:v0.11.4 |
| Namespace | default |
| Replicas | 1 (Recreate strategy) |
| Node placement | x86 k3s LXC nodes (nodeSelector kubernetes.io/arch: amd64 + picluster/lxc: "true"); follows its local-zfs volume |
| Service | ClusterIP, port 8080 |
| Ingress | Traefik IngressRoute — chat.prod-k3s.homelab.example, TLS via the shared local-example-com-tls wildcard cert |
| Storage | open-webui-data-zfs PVC, 5Gi, local-zfs storage class, mounted at /app/backend/data |
| Auto-reload | reloader.stakater.com/auto: "true" |
Configuration
Open WebUI points at an external Ollama server rather than running its own model runtime:
| Env var | Value |
|---|---|
OLLAMA_BASE_URL | https://ollama.intel.homelab.example |
ENABLE_RAG_WEB_SEARCH | True |
RAG_WEB_SEARCH_ENGINE | searxng |
RAG_WEB_SEARCH_RESULT_COUNT | 3 |
RAG_WEB_SEARCH_CONCURRENT_REQUESTS | 10 |
WEBUI_SECRET_KEY | Sourced from the open-webui-secrets Secret |
TZ | America/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.