> ## Documentation Index
> Fetch the complete documentation index at: https://docs.controlplane.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Open WebUI

> Deploy Open WebUI on Control Plane using the Template Catalog. Self-hosted, ChatGPT-style chat interface for LLMs, backed by an in-GVC Ollama server and any OpenAI-compatible API, with users, RAG, and model management on a persistent volume served over HTTPS.

## Overview

Open WebUI is a self-hosted, ChatGPT-style chat interface for large language models with user accounts, RAG (chat grounded in your uploaded documents), and model management. This template deploys a single stateful workload that keeps all of its state on a persistent volume and connects to your models through an in-GVC [Ollama](/template-catalog/templates/ollama) server and/or any OpenAI-compatible endpoint, served over HTTPS on the canonical `*.cpln.app` endpoint. Sign-ups are open on a fresh install so you can onboard immediately — the first account you register becomes the admin, and you [lock registration down](#important-notes) afterward.

### Architecture

* **Open WebUI** — A single-replica stateful workload serving the web UI and API on port `8080`. Its public `WEBUI_URL` is derived from the canonical endpoint at boot, so links resolve correctly with no manual configuration.
* **Embedded SQLite on a persistent volume** — All durable state (the `webui.db` database, uploaded files, the default Chroma vector store used for RAG, and cache) lives on the workload's volume set at `/app/backend/data`. SQLite is single-writer, so there is no external database dependency and the workload runs as exactly one replica.
* **Model backends** — Chat completions are served by an existing Ollama workload in the same GVC (default), an OpenAI-compatible API (optional), or both. Neither backend is bundled by this template — you point it at model providers you run or subscribe to.

### What Gets Created

* **Stateful Open WebUI Workload** — A single replica serving the web UI and API on port `8080`.
* **Volume Set** — A 10 GiB persistent volume mounted at `/app/backend/data` holding the SQLite database, uploaded files, the RAG vector store, and cache. Scheduled snapshots protect the data, and a final snapshot is kept on delete.
* **Config Secret** — Holds the stable `WEBUI_SECRET_KEY` that signs sessions and JWTs.
* **Start-Script Secret** — An opaque secret whose boot script sets `WEBUI_URL` from the canonical endpoint.
* **Identity & Policy** — An identity bound to the workload with a least-privilege policy granting `reveal` access to exactly the secrets it mounts (the config and start-script secrets, plus your OpenAI-key secret only when you configure one).

<Note>
  This template does not create a GVC. You must deploy it into an existing GVC.
</Note>

## Prerequisites

None for a default install — no secrets, cloud accounts, or external resources are required to bring the UI up. The items below are optional and only needed for the corresponding feature.

* **License awareness** — Open WebUI ships under the "Open WebUI License" (BSD-3-Clause plus a branding-protection clause). It is free to self-host and run in production at any scale, but you must keep the "Open WebUI" branding visible in the UI **unless** your deployment serves 50 or fewer users, or you obtain enterprise permission. See [Important Notes](#important-notes).
* **Ollama backend (recommended)** — An existing [Ollama](/template-catalog/templates/ollama) workload in the same GVC. Deploy the Ollama template first, then set its workload name in `ollama.workloadName`. Enabled by default.
* **OpenAI-compatible backend (optional)** — Create, **before installing**, an [opaque secret](https://docs.controlplane.com/reference/secret#opaque) (`encoding: plain`) in your org holding your API key, and set its name in `openai.apiKeySecretName`. An empty value leaves this backend off.

Install the template using your preferred method:

<CardGroup cols={2}>
  <Card title="UI" href="/template-catalog/install-manage/ui" icon="laptop">
    Browse, install, and manage templates visually
  </Card>

  <Card title="CLI" href="/template-catalog/install-manage/cli" icon="terminal">
    Manage templates from your terminal
  </Card>

  <Card title="Terraform" href="/template-catalog/install-manage/terraform" icon={<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><g fill-rule="evenodd"><path d="M77.941 44.5v36.836L46.324 62.918V26.082zm0 0" fill="#5c4ee5"/><path d="M81.41 81.336l31.633-18.418V26.082L81.41 44.5zm0 0" fill="#4040b2"/><path d="M11.242 42.36L42.86 60.776V23.941L11.242 5.523zm0 0M77.941 85.375L46.324 66.957v36.82l31.617 18.418zm0 0" fill="#5c4ee5"/></g></svg>}>
    Declare templates in your Terraform configurations
  </Card>

  <Card
    title="Pulumi"
    href="/template-catalog/install-manage/pulumi"
    icon={<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" id="Pulumi-Icon--Streamline-Svg-Logos" height="24" width="24">
    <desc>
        Pulumi Icon Streamline Icon: https://streamlinehq.com
    </desc>
    <path fill="#f26e7e" d="M4.683025 13.3318c0.869125 -0.5018 0.870575 -2.1264 0.003225 -3.62865s-2.27504 -2.313275 -3.1441725 -1.811475C0.672945 8.3935 0.6715 10.0181 1.53885 11.52035c0.86735 1.502275 2.27505 2.313275 3.144175 1.81145Zm0.0052 3.2167c0.86735 1.502275 0.865925 3.126875 -0.003225 3.628675 -0.86915 0.5018 -2.2768275 -0.309225 -3.144175 -1.81145 -0.8673525 -1.50225 -0.8659075 -3.126875 0.003225 -3.628675 0.8691325 -0.5018 2.276825 0.309225 3.144175 1.81145Zm5.922875 3.4243c0.86735 1.50225 0.8659 3.126775 -0.003225 3.62875 -0.869125 0.501775 -2.27685 -0.309325 -3.1442 -1.81155 -0.867325 -1.50225 -0.865875 -3.12685 0.00325 -3.628675 0.869125 -0.5018 2.276825 0.309225 3.144175 1.811475Zm-0.001925 -6.845275c0.86735 1.50225 0.8659 3.12685 -0.003225 3.628675 -0.869125 0.5018 -2.276825 -0.309225 -3.144175 -1.811475 -0.86735 -1.50225 -0.8659 -3.12685 0.003225 -3.62865 0.869125 -0.501825 2.276825 0.3092 3.144175 1.81145Z" stroke-width="0.25"></path>
    <path fill="#8a3391" d="M22.45775 11.524125c0.86725 -1.502225 0.865925 -3.12685 -0.003225 -3.62865 -0.869125 -0.501825 -2.276825 0.3092 -3.144175 1.811475 -0.86735 1.50225 -0.8659 3.126825 0.003225 3.62865 0.869125 0.501825 2.276825 -0.3092 3.144175 -1.811475Zm0.000175 3.2151c0.869075 0.5018 0.870625 2.1264 0.003225 3.62865 -0.86735 1.50225 -2.27505 2.313275 -3.144175 1.81145 -0.869125 -0.5018 -0.870575 -2.126425 -0.003225 -3.62865 0.86735 -1.50225 2.27505 -2.313275 3.144175 -1.81145ZM16.536225 18.157875c0.86915 0.501825 0.8706 2.126425 0.00325 3.628675 -0.86735 1.502125 -2.275075 2.313225 -3.1442 1.81145 -0.869125 -0.50175 -0.870575 -2.126425 -0.003225 -3.62865 0.867375 -1.502275 2.27505 -2.3133 3.144175 -1.811475Zm-0.003325 -6.843775c0.869125 0.5018 0.870575 2.126425 0.003225 3.628675s-2.27505 2.313275 -3.1442 1.811475c-0.869125 -0.501825 -0.870575 -2.126425 -0.003225 -3.628675 0.86735 -1.502275 2.27505 -2.313275 3.1442 -1.811475Z" stroke-width="0.25"></path>
    <path fill="#f7bf2a" d="M15.138225 2.06721c0 1.003615 -1.40625 1.817215 -3.14095 1.817215 -1.7347 0 -3.14095 -0.8136 -3.14095 -1.817215C8.856325 1.06359 10.262575 0.25 11.997275 0.25c1.7347 0 3.14095 0.81359 3.14095 1.81721ZM9.2166 5.482375c0 1.003625 -1.40625 1.8172 -3.14095 1.8172 -1.7347 0 -3.14095 -0.813575 -3.14095 -1.8172s1.40625 -1.817225 3.14095 -1.817225c1.7347 0 3.14095 0.8136 3.14095 1.817225Zm8.71005 1.8172c1.7347 0 3.14095 -0.813575 3.14095 -1.8172s-1.40625 -1.817225 -3.14095 -1.817225c-1.7347 0 -3.14095 0.8136 -3.14095 1.817225s1.40625 1.8172 3.14095 1.8172Zm-2.788425 1.605625c0 1.003625 -1.40625 1.8172 -3.14095 1.8172 -1.7347 0 -3.14095 -0.813575 -3.14095 -1.8172 0 -1.0036 1.40625 -1.8172 3.14095 -1.8172 1.7347 0 3.14095 0.8136 3.14095 1.8172Z" stroke-width="0.25"></path>
    </svg>}
  >
    Declare templates in your Pulumi programs
  </Card>
</CardGroup>

## Configuration

The default `values.yaml` for this template:

```yaml theme={null}
image: ghcr.io/open-webui/open-webui:v0.11.0

resources:
  cpu: 1        # max vCPU
  memory: 2Gi   # max memory (RAG loads a local embedding model into RAM on first use)
  minCpu: 500m
  minMemory: 1Gi

# ─── Persistence ──────────────────────────────────────────────────────────────
# One per-replica volume holds everything durable: SQLite webui.db, uploaded
# files, the default Chroma vector store (RAG), and cache. Mounts /app/backend/data.
volumeset:
  capacity: 10 # GiB (platform minimum 10)

# ─── Backup ───────────────────────────────────────────────────────────────────
# Platform-managed crash-consistent snapshots (no cloud account/bucket needed).
backup:
  enabled: true
  schedule: "0 3 * * *" # cron in UTC — daily 03:00 (hourly is the platform max)
  retention: 7d         # how long each snapshot is kept (e.g. 7d, 720h, 30d)

# ─── Authentication ───────────────────────────────────────────────────────────
auth:
  # Signs sessions/JWTs. Override ONCE at install (openssl rand -base64 32).
  # Must stay STABLE across upgrades — changing it logs every user out.
  webuiSecretKey: "CHANGE-ME-openssl-rand-base64-32-abcdEFGH1234"
  enableSignup: true # first registered user becomes ADMIN — turn OFF after onboarding

# ─── Model backends ───────────────────────────────────────────────────────────
# Point at an existing `ollama` template deployment in this same GVC.
ollama:
  enabled: true
  workloadName: ollama # the ollama workload's name in this GVC
  port: 11434
  # → OLLAMA_BASE_URL = http://{workloadName}.{gvc}.cpln.local:{port}

# Optional OpenAI-compatible provider. The API key is a PREREQUISITE opaque
# secret (encoding: plain) you create BEFORE install; reference it by name here.
# Empty apiKeySecretName = this backend is off.
openai:
  baseUrl: https://api.openai.com/v1 # any OpenAI-compatible endpoint
  apiKeySecretName: "" # e.g. my-openwebui-openai-key ; empty = OpenAI backend off

# ─── Access ───────────────────────────────────────────────────────────────────
customDomain: "" # full URL, e.g. https://chat.example.com ; empty = canonical *.cpln.app

publicAccess:
  enabled: true # serve the UI over public HTTPS on the canonical *.cpln.app endpoint

internalAccess: # inbound firewall scope for in-GVC callers of the Open WebUI API
  type: none # options: none, same-gvc, same-org, workload-list
  workloads: [] # used with workload-list
```

### Instance & Resources

* `image` — The Open WebUI container image.
* `resources` — CPU and memory for the container. RAG loads a local embedding model into RAM on first use, so keep memory at or above the default.
* `volumeset.capacity` — Volume size in GiB (minimum 10) for the SQLite database, uploads, RAG vector store, and cache.

### Backup

Scheduled, crash-consistent snapshots of the data volume, managed by the platform — no cloud account or bucket is required. See [Backing Up](#backing-up) for how snapshots and restores work.

* `backup.enabled` — Take periodic snapshots of the data volume (default `true`).
* `backup.schedule` — Cron expression in UTC (default `0 3 * * *`, daily at 03:00). The platform does not accept schedules more frequent than hourly.
* `backup.retention` — How long each snapshot is kept, e.g. `7d`, `720h`, `30d`.

### Authentication

* `auth.webuiSecretKey` — Signs session tokens and JWTs. Override it **once** at install with `openssl rand -base64 32`, then keep it stable forever — see [Important Notes](#important-notes).
* `auth.enableSignup` — Open registration on the public endpoint (default `true` so a fresh install is usable). The first account registered becomes the admin; **turn this off after onboarding** — see [Important Notes](#important-notes).

### Model backends

At least one backend is needed to actually chat. The Ollama backend is on by default; the OpenAI-compatible backend is off until you supply a key secret. You can enable both.

* `ollama.enabled` — Connect to an existing Ollama workload in this GVC (default `true`).
* `ollama.workloadName` — The Ollama workload's name in this GVC. The base URL is derived as `http://{workloadName}.{gvc}.cpln.local:{port}`.
* `ollama.port` — The Ollama API port (default `11434`).
* `openai.baseUrl` — Any OpenAI-compatible endpoint (default `https://api.openai.com/v1`).
* `openai.apiKeySecretName` — Name of your pre-created opaque secret holding the API key (see [Prerequisites](#prerequisites)). Empty (default) leaves the OpenAI backend off.

<Warning>
  Model-backend settings are read from the environment only on the **first** boot and are then stored in the app database. Changing `ollama.workloadName` or `openai.*` via a later `helm upgrade` is ignored — update model connections afterward from the admin UI under **Settings → Connections**. See [Important Notes](#important-notes).
</Warning>

### Access

* `customDomain` — Full URL of a custom domain, e.g. `https://chat.example.com`. Empty (default) uses the canonical `*.cpln.app` endpoint.
* `publicAccess.enabled` — Serve the UI over public HTTPS on the canonical `*.cpln.app` endpoint (default). When disabled, external requests are blocked at the edge and only in-GVC callers reach it per `internalAccess`.
* `internalAccess.type` — Internal firewall scope for in-GVC callers of the Open WebUI API:

| Type            | Description                                                            |
| --------------- | ---------------------------------------------------------------------- |
| `none`          | No internal access (default).                                          |
| `same-gvc`      | Allow access from all workloads in the same GVC.                       |
| `same-org`      | Allow access from all workloads in the same organization.              |
| `workload-list` | Allow access only from workloads listed in `internalAccess.workloads`. |

## Connecting

| What                 | Value                                                                                 |
| -------------------- | ------------------------------------------------------------------------------------- |
| Web UI (public)      | `https://<canonical>.cpln.app` — `status.canonicalEndpoint` of `{release}-open-webui` |
| Internal (if opened) | `http://{release}-open-webui.{gvc}.cpln.local:8080`                                   |
| Ollama backend       | `http://{ollama.workloadName}.{gvc}.cpln.local:11434` (the existing Ollama workload)  |
| Login                | The account you register in the UI — the first registration becomes the admin         |

### Using a Model Backend

Deploy the [Ollama](/template-catalog/templates/ollama) template into the same GVC and pull at least one model, then install Open WebUI with `ollama.workloadName` set to that workload's name — its models appear in the model picker automatically. To use a hosted provider instead, create the API-key secret (see [Prerequisites](#prerequisites)), set `openai.apiKeySecretName`, and Open WebUI lists that provider's models. If a configured Ollama backend is unreachable the UI still boots and simply shows no Ollama models — confirm `ollama.workloadName` names a `ready` Ollama workload in the same GVC.

## Backing Up

Backups are **scheduled volume snapshots** managed by the platform — no cloud account or bucket is required. On the configured cron schedule the platform takes a crash-consistent snapshot of the data volume; SQLite recovers cleanly from one. Snapshots are pruned automatically after `backup.retention`, and a final snapshot is always taken when the release is uninstalled.

* **Default schedule** — Daily at 03:00 UTC (`backup.schedule: "0 3 * * *"`), kept for 7 days (`backup.retention: 7d`).
* **Minimum interval** — The platform does not accept schedules more frequent than hourly.

List the snapshots for the release's volume set:

```bash theme={null}
cpln volumeset snapshot get {release}-open-webui-data --gvc {gvc} -o yaml
```

<Note>
  Snapshots live in the platform storage layer alongside the volume, not off-site. They protect against data corruption and accidental changes, but losing the whole GVC would lose them too.
</Note>

## Restoring a Backup

Restore is **in-place** on the release's own volume set: the platform provisions a fresh volume from the chosen snapshot and swaps it in, then the workload restarts to remount it.

<Warning>
  Restoring reverts the volume to the exact snapshot state — any changes made after that snapshot are lost — and restarts the single-replica workload, so the UI is briefly unavailable during the swap.
</Warning>

<Steps>
  <Step title="Find the snapshot to restore">
    List snapshots and note the `name`, `location`, and `volumeIndex` of the one you want:

    ```bash theme={null}
    cpln volumeset snapshot get {release}-open-webui-data --gvc {gvc} -o yaml
    ```
  </Step>

  <Step title="Restore it in place">
    Provision a fresh volume from the snapshot and swap it in. The workload restarts to remount it:

    ```bash theme={null}
    cpln volumeset snapshot restore {release}-open-webui-data \
      --snapshot-name <snapshot-name> \
      --location <location> \
      --volume-index 0 \
      --gvc {gvc}
    ```
  </Step>

  <Step title="Verify">
    Once the workload is ready again, log in and confirm your chats and settings are present.
  </Step>
</Steps>

## Important Notes

* **License / branding clause** — You must keep the "Open WebUI" branding visible in the UI **unless** your deployment serves 50 or fewer users, or you have enterprise permission. Removing the branding outside those cases violates the license; it is not a template setting.
* **The first user to register becomes the admin.** Sign-ups are open by default so the install is immediately usable, which means anyone reaching the public endpoint can register while it is open. Register your admin account first, then set `auth.enableSignup=false` to lock it down.
* **`auth.webuiSecretKey` must never change after first install.** It is the key that signs session tokens and JWTs. Rotating it — or letting a fresh volume regenerate one — logs every user out. Override it once with `openssl rand -base64 32` and keep it stable.
* **Single replica, by design.** The embedded SQLite is single-writer and the volume set is per-replica, so the workload is pinned to one replica with no `replicas` knob. A restart or upgrade is a brief full outage (about a minute).
* **Model-backend settings apply at install, then persist in the app database.** `ollama.workloadName` and `openai.*` are read from the environment only on the first boot and then stored in `webui.db`. Changing them via a later `helm upgrade` is silently ignored — update model connections afterward from the admin UI (**Settings → Connections**).
* **Data lives only on the volume set.** Uninstall deletes it (a final snapshot is taken first); a reinstall starts empty. Changing the secret and redeploying does not re-key existing data.
* **Backups are in-platform, not off-site.** Scheduled snapshots and the final snapshot on uninstall live in the platform storage layer next to the volume; losing the whole GVC would lose them too. See [Backing Up](#backing-up).

## External References

<CardGroup cols={2}>
  <Card title="Open WebUI on GitHub" icon="github" href="https://github.com/open-webui/open-webui">
    Upstream source repository
  </Card>

  <Card title="Open WebUI Documentation" icon="book" href="https://docs.openwebui.com/">
    Official documentation and getting-started guides
  </Card>

  <Card title="Environment Variable Reference" icon="gear" href="https://docs.openwebui.com/reference/env-configuration/">
    Full list of supported configuration variables
  </Card>

  <Card title="License" icon="scale-balanced" href="https://github.com/open-webui/open-webui/blob/main/LICENSE">
    The Open WebUI License and its branding clause
  </Card>

  <Card title="Ollama Template" icon="server" href="/template-catalog/templates/ollama">
    Deploy the in-GVC Ollama model backend
  </Card>

  <Card title="Open WebUI Template" icon="github" href="https://github.com/controlplane-com/templates/tree/main/open-webui">
    View the source files, default values, and chart definition
  </Card>
</CardGroup>
