[GH-ISSUE #427] open-webui Helm + terminals: persistence defaults not applied in operator flow + duplicate env when overriding terminal connection #138

Open
opened 2026-10-18 21:06:33 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @rich-nahra on GitHub (Aug 8, 2026).
Original GitHub issue: https://github.com/open-webui/helm-charts/issues/427

Using open-webui chart (16.0.0) with terminals subchart (0.5.0) on k3s.

Configured:

terminals:
  enabled: true
  terminalDefaults:
    persistence:
      enabled: true
      size: 5Gi
      storageClass: proxmox-lvm

Issue 1: spawned Terminal CRs still get spec.persistence.enabled: false (no PVC), unless policy storage is explicitly set.
This makes terminalDefaults.persistence.enabled ineffective for operator provisioning path.

Issue 2: trying to set TERMINAL_SERVER_CONNECTIONS via extraEnvVars to use /p/default causes Helm SSA failure because chart already injects TERMINAL_SERVER_CONNECTIONS when terminals.enabled=true:

.spec.template.spec.containers[name="open-webui"].env: duplicate entries for key [name="TERMINAL_SERVER_CONNECTIONS"]

Issue 3: there is no Helm-native/declarative way to create or reconcile terminal policies (e.g., default policy with storage and storage_mode).
Current options are manual UI/API calls or custom post-sync jobs.

Expected

  • Either defaults should be honored for operator flow, or
  • chart should expose first-class values to control terminal connection policy route and policy definitions declaratively.

Suggested enhancements

  • Connection override values, e.g.:
    • terminals.connection.path (e.g. /p/default), or
    • terminals.connection.policyId, or
    • terminals.connection.urlOverride
  • Declarative policy values, e.g.:
    • terminals.policies map/list reconciled by chart/operator (create/update semantics), including fields like storage, storage_mode, limits, image, etc.
  • Docs clarifying precedence between CRD terminalDefaults and policy-derived spec in kubernetes-operator mode.

Originally created by @rich-nahra on GitHub (Aug 8, 2026). Original GitHub issue: https://github.com/open-webui/helm-charts/issues/427 Using open-webui chart (16.0.0) with terminals subchart (0.5.0) on k3s. Configured: ```yaml terminals: enabled: true terminalDefaults: persistence: enabled: true size: 5Gi storageClass: proxmox-lvm ``` **Issue 1:** spawned Terminal CRs still get `spec.persistence.enabled: false` (no PVC), unless policy `storage` is explicitly set. This makes `terminalDefaults.persistence.enabled` ineffective for operator provisioning path. **Issue 2:** trying to set `TERMINAL_SERVER_CONNECTIONS` via `extraEnvVars` to use `/p/default` causes Helm SSA failure because chart already injects `TERMINAL_SERVER_CONNECTIONS` when `terminals.enabled=true`: ```text .spec.template.spec.containers[name="open-webui"].env: duplicate entries for key [name="TERMINAL_SERVER_CONNECTIONS"] ``` **Issue 3:** there is no Helm-native/declarative way to create or reconcile terminal policies (e.g., `default` policy with `storage` and `storage_mode`). Current options are manual UI/API calls or custom post-sync jobs. **Expected** - Either defaults should be honored for operator flow, or - chart should expose first-class values to control terminal connection policy route and policy definitions declaratively. **Suggested enhancements** - Connection override values, e.g.: - `terminals.connection.path` (e.g. `/p/default`), or - `terminals.connection.policyId`, or - `terminals.connection.urlOverride` - Declarative policy values, e.g.: - `terminals.policies` map/list reconciled by chart/operator (create/update semantics), including fields like `storage`, `storage_mode`, limits, image, etc. - Docs clarifying precedence between CRD `terminalDefaults` and policy-derived spec in `kubernetes-operator` mode. ---
Author
Owner

@wa91h commented on GitHub (Sep 18, 2026):

Confirming all three on open-webui 16.5.0 + terminals 0.7.0 (images 0.2.4) on k3s 1.36, and adding what actually made it work end to end, in case it helps whoever picks this up:

Issue 1 (persistence) — root cause is in the orchestrator, not the chart: backends/kubernetes_operator.py writes persistence.enabled: true only when the resolved spec has storage, and the un-prefixed proxy route does no policy lookup at all ("Uses settings.* defaults — no policy lookup"), so terminalDefaults.persistence can never apply on that path. A policy with storage reached through /p/<policy> gives a PVC that the operator deliberately creates without an ownerReference, so it survives idle reaps and CR re-creates. That part is solid.

Issue 2 (duplicate env) — we ended up running terminals as its own release with terminals.enabled: false on the open-webui chart. Naming the release so terminals.fullname resolves to the same string the subchart produced (open-webui-terminals) keeps the six objects' names and the orchestrator URL unchanged, and the open-webui chart then emits no TERMINAL_SERVER_CONNECTIONS, so it can be declared once in extraEnvVars (TERMINALS_API_KEY from the Secret first, then the JSON with /p/<policy> + chat_uploads). On an existing install it has to be two applies — open-webui first, so Helm removes the subchart objects before the new release adopts the names.

Issue 3 (declarative policies) — a PUT /api/v1/policies/<id> from a post-install hook / Terraform null_resource works, but only if the orchestrator's DB is not the in-pod sqlite: the chart gives the orchestrator no volume, so a restart erases the policy and /p/<policy> 404s. TERMINALS_DATABASE_URL → Postgres via orchestrator.extraEnvVars fixed that (asyncpg/psycopg are in the image; alembic runs at startup).

Two more things found on the way, filed separately: the chart's CRD is missing spec.env/contextId/podTemplate/restricted/securityContexts and prunes them silently (#442), and on the named-policy route the orchestrator prefers TERMINALS_IMAGE (default :latest) over the chart's pinned TERMINALS_KUBERNETES_IMAGE (open-webui/terminals#64; the idle-timeout 0 = 30 min one is open-webui/terminals#63) — so a policy-provisioned pod on this chart pulls open-terminal:latest unless TERMINALS_IMAGE is also set.

A terminals.connection.policyId value plus terminals.policies reconciled by the chart, as suggested above, would remove every step of this.

<!-- gh-comment-id:5722873373 --> @wa91h commented on GitHub (Sep 18, 2026): Confirming all three on open-webui 16.5.0 + terminals 0.7.0 (images 0.2.4) on k3s 1.36, and adding what actually made it work end to end, in case it helps whoever picks this up: **Issue 1 (persistence)** — root cause is in the orchestrator, not the chart: `backends/kubernetes_operator.py` writes `persistence.enabled: true` only when the resolved spec has `storage`, and the un-prefixed proxy route does no policy lookup at all (`"Uses settings.* defaults — no policy lookup"`), so `terminalDefaults.persistence` can never apply on that path. A policy with `storage` reached through `/p/<policy>` gives a PVC that the operator deliberately creates **without an ownerReference**, so it survives idle reaps and CR re-creates. That part is solid. **Issue 2 (duplicate env)** — we ended up running `terminals` as **its own release** with `terminals.enabled: false` on the open-webui chart. Naming the release so `terminals.fullname` resolves to the same string the subchart produced (`open-webui-terminals`) keeps the six objects' names and the orchestrator URL unchanged, and the open-webui chart then emits no `TERMINAL_SERVER_CONNECTIONS`, so it can be declared once in `extraEnvVars` (`TERMINALS_API_KEY` from the Secret first, then the JSON with `/p/<policy>` + `chat_uploads`). On an existing install it has to be two applies — open-webui first, so Helm removes the subchart objects before the new release adopts the names. **Issue 3 (declarative policies)** — a `PUT /api/v1/policies/<id>` from a post-install hook / Terraform `null_resource` works, but only if the orchestrator's DB is not the in-pod sqlite: the chart gives the orchestrator no volume, so a restart erases the policy and `/p/<policy>` 404s. `TERMINALS_DATABASE_URL` → Postgres via `orchestrator.extraEnvVars` fixed that (asyncpg/psycopg are in the image; alembic runs at startup). Two more things found on the way, filed separately: the chart's CRD is missing `spec.env`/`contextId`/`podTemplate`/`restricted`/securityContexts and prunes them silently (#442), and on the named-policy route the orchestrator prefers `TERMINALS_IMAGE` (default `:latest`) over the chart's pinned `TERMINALS_KUBERNETES_IMAGE` (open-webui/terminals#64; the idle-timeout `0` = 30 min one is open-webui/terminals#63) — so a policy-provisioned pod on this chart pulls `open-terminal:latest` unless `TERMINALS_IMAGE` is also set. A `terminals.connection.policyId` value plus `terminals.policies` reconciled by the chart, as suggested above, would remove every step of this.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
open-webui/helm-charts#138
No description provided.