Open WebUI on Kubernetes without Helm, with Kapitan
Open WebUI 0.12.5, a web interface and API for chatting with language models, on SQLite with Valkey for its websockets, rendered by the kadet-hub kubernetes generator 1.14.0 from Open WebUI’s Helm chart 17.5.0. Ollama and OpenAI-compatible endpoints are options.
- Latest version:
1.0.1, published - Source chart:
oci://ghcr.io/open-webui/helm-charts/open-webui:17.5.0@sha256:93635790db231b584041cd11c3fa0d80e3238d906ab8bf4dcb2bc055ad733527 - Proof level:
deploys, compared with the chart by the kadet-hub/recipes CI renderspassed in the release run of with check 0.18.0, kind v0.33.0- Output capabilities: none
- Inventory backends:
omegaconf - Generators: kubernetes 1.14.0
sha256:787129e1eaed6b9bc868fe4c4aec58d40de6a89fc3cc08424a4cb5822b855080 - Image security: grade F 2761 findings, one per advisory and package, in the 1 image of version 1.0.1: CRITICAL 14, HIGH 376, MEDIUM 1254, LOW 1096, UNKNOWN 21. Scanned 2026-11-07 11:47 UTC. Full report
The grade rates the upstream images the recipe pins, not the recipe:ghcr.io/open-webui/open-webui.
What it deploys
recipes.open-webui(init.yml)recipes.open-webui.open-webui(open-webui.yml):open-webuirecipes.open-webui.ollama(ollama.yml), an option:open-webuirecipes.open-webui.openai(openai.yml), an option:open-webui
Required parameters
applications.open-webui.secret_key, as a ref. Open WebUI signs its logins with it. Without it the image generates a key in each new container, so every restart signs every user out.applications.valkey.password, as a ref, for the included recipevalkey. It is part of the Redis URL in the Secretopen-webui, so use letters and digits only.- With
recipes.open-webui.openai:applications.open-webui.openai.urlandapplications.open-webui.openai.api_key, the key as a ref.
Without one of them the compile stops with Interpolation key ... not found and that key.
Include
A target includes the recipe and its options as classes and can override anything the recipe sets:
classes:
- recipes.open-webui
# Ollama in the same namespace, through the included recipe ollama
- recipes.open-webui.ollama
# An OpenAI-compatible endpoint, such as vLLM, SGLang or a hosted API
- recipes.open-webui.openai
parameters:
namespace: open-webui
kapitan:
vars:
target: open-webui
applications:
open-webui:
secret_key: <ref>
openai:
url: https://llm.example.com/v1
api_key: <ref>
valkey:
password: <ref>
Fetching it
The quickstart goes through these steps on a kind cluster with the uptime-kuma recipe, from installing Kapitan to the running app.
A separate fetch inventory pins the recipe by version and digest. This is fetch/targets/recipes.yml for version 1.0.1:
parameters:
kapitan:
dependencies:
- type: oci
source: ghcr.io/kadet-hub/recipes/open-webui:1.0.1@sha256:3af3e706db37531ed72ecfe3810a4d3cd726f3f5ca5ef5ac066ec51bffabebd7
output_path: inventory/classes/recipes/open-webui
Version 1.0.1 includes ollama 1.0.1 and valkey 1.0.3. The consumer workflow adds the included recipes at the digests the index lists. Kapitan's --fetch reads no index, so for a local compile pull them by digest first:
tmp=$(mktemp -d)
oras pull -o "$tmp" ghcr.io/kadet-hub/recipes/ollama@sha256:7d1081b5c348b8c6e119af4a972b91a5543e0fad1f92d494c8a86bd0026d7db2
mkdir -p inventory/classes/recipes/ollama
tar -xf "$tmp/ollama.tar" -C inventory/classes/recipes/ollama --no-same-owner
oras pull -o "$tmp" ghcr.io/kadet-hub/recipes/valkey@sha256:a50d43cf9080b58040cf84909b0cd7497392709a23f5759e985bd912a9137ce5
mkdir -p inventory/classes/recipes/valkey
tar -xf "$tmp/valkey.tar" -C inventory/classes/recipes/valkey --no-same-owner
The first command fetches the recipe into inventory/classes/recipes/open-webui, the second the generators and compiles:
kapitan compile --inventory-path fetch --fetch --output-path .
kapitan compile --fetch
The first command exits with status 1 because the fetch target compiles nothing. Kapitan's --fetch checks neither the digest nor the attestation. This verifies the attestation of the recipe and of the recipes it includes:
gh attestation verify \
oci://ghcr.io/kadet-hub/recipes/open-webui@sha256:3af3e706db37531ed72ecfe3810a4d3cd726f3f5ca5ef5ac066ec51bffabebd7 \
--owner kadet-hub \
--cert-identity https://github.com/kadet-hub/registry/.github/workflows/release.yml@refs/heads/main
gh attestation verify \
oci://ghcr.io/kadet-hub/recipes/ollama@sha256:7d1081b5c348b8c6e119af4a972b91a5543e0fad1f92d494c8a86bd0026d7db2 \
--owner kadet-hub \
--cert-identity https://github.com/kadet-hub/registry/.github/workflows/release.yml@refs/heads/main
gh attestation verify \
oci://ghcr.io/kadet-hub/recipes/valkey@sha256:a50d43cf9080b58040cf84909b0cd7497392709a23f5759e985bd912a9137ce5 \
--owner kadet-hub \
--cert-identity https://github.com/kadet-hub/registry/.github/workflows/release.yml@refs/heads/main
The attested index must also list each digest under its recipe with the pinned version, and not as yanked. Verifying by hand shows how to read it.
Settings
<c> stands for components.open-webui.
| Chart value | Inventory |
|---|---|
image.tag |
<c>.image, tag and digest |
persistence.size |
applications.open-webui.storage |
persistence.storageClass |
<c>.persistent_volume_claims.open-webui.storage_class |
extraEnvVars |
<c>.env, a mapping of name to value |
resources |
<c>.resources |
service.type |
<c>.service.type |
readinessProbe, livenessProbe, startupProbe |
<c>.healthcheck.readiness, .liveness, .startup |
nodeSelector, tolerations, affinity |
<c>.node_selector, <c>.tolerations, <c>.affinity |
podSecurityContext, containerSecurityContext |
<c>.workload_security_context, <c>.security_context |
sso.* |
<c>.env with Open WebUI’s OAUTH_* and OPENID_* variables |
databaseUrl |
<c>.env.DATABASE_URL as a secretKeyRef, not tested |
The chart’s Pipelines and Ollama subcharts are off in the recipe. Ollama
comes from the option ollama instead. The chart’s own Redis is replaced
by the included recipe valkey. Tika, Terminals, the Ingress, the
HTTPRoute, GKE’s ManagedCertificate and S3, GCS or Azure storage are off by
default and not part of the recipe.
Any list set in the target is appended to the recipe’s list. To replace
one, set the key to ~ in a class included after the recipe and the new
list in the target.
Proof
check open-webui --level deploys with tests/values.yaml and
tests/target.yml, on kind for each Kubernetes minor CI tests. The target
includes both options. tests/values.yaml turns the chart’s Ollama,
Pipelines and Redis off, points the chart at ollama and valkey, and
creates the Secret open-webui through extraResources, as a user would
next to the chart. It sets the recipe’s probe as readinessProbe. It gives the Ollama and OpenAI variables through
extraEnvVars, in the order the options add them, and sets
allowPrivilegeEscalation: false on both containers, because check
does not accept the empty securityContext that the generator renders on
an init container.
The five objects differ in one way. The StatefulSet and the Service select
on name, the chart on app.kubernetes.io/instance and component, and
both select the same pods. The chart binds no role. The objects of ollama
and valkey are proven by their own recipes.
tests/smoke requires /health through the Service. It signs up the first account, which becomes admin, and
requires 403 for a second signup.
It starts an OpenAI-compatible stub, pulls smollm:135m into Ollama
through Open WebUI’s /ollama/api/pull, finds both models in
/api/models and gets a chat completion from each through
/api/chat/completions. Valkey must hold keys of Open WebUI, and the
admin’s token must still work after the pod restarted. It prints how long
the pull and the completion took.
Used in stacks
Versions
1.0.1, :sha256:3af3e706db37531ed72ecfe3810a4d3cd726f3f5ca5ef5ac066ec51bffabebd71.0.0, :sha256:f44fd8d69166996694c83eeb6951e95699dc8601368d0f42259068c20a0c913c
The recipe's files are in kadet-hub/recipes. All recipes