Open-WebUI#

Open-WebUI runs on ereshkigal as a Podman OCI container managed by the tsunaminoai.openWebui NixOS module (modules/nixos/containers/open-webui/default.nix). It is the LLM chat front-end for the local stack and doubles as a RAG knowledge base over the Paperless-NGX document library. All inference is delegated to Ollama on mokou over Tailscale — see the AI overview for the full topology.

  • Web UI (HTTP): http://ereshkigal:3000
  • Web UI (HTTPS): https://ereshkigal.<tailscaleDomain>:3001 (when ACME is active)
  • Module option: tsunaminoai.openWebui.enable = true;

Architecture#

The container is ghcr.io/open-webui/open-webui:main, run on the openwebui_default Podman network with the alias open-webui. The host port (default 3000) maps to container port 8080. Persistent state — including the embedded ChromaDB vector store — lives in the named Podman volume openwebui_data (/app/backend/data).

Chat and RAG embeddings both go to Ollama on mokou via the ollamaHost option, which sets OLLAMA_BASE_URL to http://<ollamaHost>:11434. RAG uses the ollama embedding engine backed by nomic-embed-text; web search is disabled (ENABLE_RAG_WEB_SEARCH = "false") so retrieval stays local. The container is started with --add-host=host.containers.internal:host-gateway so it can reach mokou through the host’s Tailscale routing.

WEBUI_AUTH = "true", so login is required and the first user to register becomes the admin.

Note

When tsunaminoai.pki.acme.enable is true, the module also stands up an nginx vhost on port + 1 (3001) that reverse-proxies the web UI over TLS using the host’s step-ca ACME cert (useACMEHost = ereshkigal.<tailscaleDomain>). WEBUI_URL is set to that HTTPS origin so absolute links and CSRF/CORS checks behave behind the proxy. The firewall opens port, plus port + 1 only when ACME is active.

Enabling the module#

# hosts/x86_64-nixos/ereshkigal/default.nix
tsunaminoai.openWebui = {
  enable = true;
  ollamaHost = "mokou.${config.tsunaminoai.nix.tailscaleDomain}";
  port = 3000;
  paperlessPort = 8011;
};

Module options#

Option Default Description
enable false Enable Open-WebUI
ollamaHost "localhost" Hostname/IP of the Ollama server (chat + embeddings); use mokou’s Tailscale FQDN
port 3000 Host port for Open-WebUI (HTTP); HTTPS is port + 1
paperlessPort 8011 Port Paperless-NGX listens on (used by the sync timer)

Environment variables#

Variable Value Purpose
OLLAMA_BASE_URL http://<ollamaHost>:11434 Chat inference endpoint
WEBUI_AUTH "true" Require login; first user becomes admin
WEBUI_URL https://<host>:3001 Public URL for link generation / CSRF
RAG_EMBEDDING_ENGINE "ollama" RAG embedding backend
RAG_EMBEDDING_MODEL "nomic-embed-text" Embedding model on mokou
OLLAMA_BASE_URL_FOR_EMBEDDINGS http://<ollamaHost>:11434 Embedding endpoint
ENABLE_RAG_WEB_SEARCH "false" Keep RAG local — no outbound web search
VECTOR_DB "chroma" Embedded ChromaDB in openwebui_data

Paperless → Open-WebUI RAG sync#

A nightly systemd timer, paperless-openwebui-sync (OnCalendar = 02:00, Persistent so it catches up after downtime), pulls already-OCR’d Paperless-NGX documents and upserts them into an Open-WebUI Knowledge collection via the Knowledge API. The one-shot service reads two sops secrets at start (ExecStartPre writes them to a runtime EnvironmentFile):

  • paperless/api-token — Paperless admin → Profile → API Token
  • openwebui/api-key — Open-WebUI → Settings → API Keys

Both must be created after first boot. The sync talks to Paperless at http://127.0.0.1:<paperlessPort> and Open-WebUI at http://127.0.0.1:<port>.

Dashboard#

When tsunaminoai.homer.enable is set, the module registers a Homer tile (“Open-WebUI”, under the Media group, ai tag) pointing at the HTTPS origin when ACME is active, otherwise the plain HTTP URL.