Skip to main content

Policies

Policies are named environment profiles that define what a terminal container looks like: its image, resource limits, storage, environment variables, and idle timeout. They let you offer different terminal environments to different teams from a single orchestrator.

For example, you might create a data-science policy with a large image, 4 CPU cores, and 16 GiB of memory, while a development policy uses the default slim image with 1 CPU and 2 GiB.


How policies workโ€‹

  1. Admin creates policies on the orchestrator via its REST API (see API reference below).
  2. Admin creates terminal connections in Open WebUI under Settings โ†’ Connections โ†’ Open Terminal. Each connection includes a policy_id field that maps it to a policy on the orchestrator.
  3. Users open a terminal. Open WebUI routes the request through /p/{policy_id}/..., and the orchestrator provisions (or reuses) a container matching that policy's spec.

Each user gets their own isolated container per policy. If a user has access to two connections with different policies, they get two independent terminals.


Policy fieldsโ€‹

All fields are optional. When a field is omitted, the orchestrator falls back to its global default (set via environment variables).

FieldTypeDefaultDescription
imagestringTERMINALS_IMAGE ยท ghcr.io/open-webui/open-terminal:latestContainer image to run
cpu_limitstringNo limitMaximum CPU (e.g., "2", "500m")
memory_limitstringNo limitMaximum memory (e.g., "4Gi", "512Mi")
storagestringNone (ephemeral)Persistent volume size (e.g., "10Gi"). When absent, the container uses ephemeral storage that is lost when the container is removed.
storage_modestringTERMINALS_KUBERNETES_STORAGE_MODE ยท per-userHow persistent volumes are provisioned: per-user, shared, or shared-rwo. See Storage modes. Only applies to Kubernetes backends.
envobject{}Key-value environment variables injected into the container
idle_timeout_minutesintegerTERMINALS_IDLE_TIMEOUT_MINUTES ยท 0 (disabled)Minutes of inactivity before the container is stopped and removed

Storage modesโ€‹

The storage_mode field controls how persistent volumes are allocated on Kubernetes backends. It has no effect on the Docker backend (which always bind-mounts a host directory).

ModeBehaviorPVC access mode
per-userEach user gets their own PVC. Full isolation.ReadWriteOnce
sharedA single PVC is shared by all users, with each user's data in a subPath under their user ID. Requires a storage class that supports ReadWriteMany (e.g., NFS, EFS).ReadWriteMany
shared-rwoA single ReadWriteOnce PVC is shared. All terminal pods are scheduled to the same node via pod affinity (Kubernetes ensures they all land on the machine that has the volume mounted). Useful when ReadWriteMany storage is unavailable.ReadWriteOnce

ReadWriteOnce (RWO) means the volume can only be mounted by pods on a single node at a time. ReadWriteMany (RWX) means multiple nodes can mount and write to the volume simultaneously.

Environment variablesโ€‹

The env field injects arbitrary key-value pairs as environment variables in the terminal container. Common uses:

  • API keys: give users access to LLM APIs, cloud services, etc.
  • Egress filtering: set OPEN_TERMINAL_ALLOWED_DOMAINS to restrict outbound network access (e.g., "*.pypi.org,github.com"). When this variable is present, the Docker backend automatically adds the NET_ADMIN capability to the container.
  • Custom configuration: any setting your terminal image supports
warning

Environment variables in a policy are visible to the terminal user (they can run env in the shell). Do not store secrets here that users should not see.


Managing policiesโ€‹

Policies are managed from the Open WebUI admin panel under Settings โ†’ Connections โ†’ Open Terminal. From there you can create, edit, and delete policies, assign them to terminal connections, and restrict access by group.

info

Updating a policy does not affect running terminals. The new spec applies the next time a container is provisioned for that policy (e.g., after the old one is reaped by idle timeout or manually deleted).


Connecting policies to Open WebUIโ€‹

Once a policy exists on the orchestrator, you wire it up in Open WebUI so users can reach it.

1. Add a terminal connectionโ€‹

In the Open WebUI admin panel, go to Settings โ†’ Connections and add an Open Terminal connection:

FieldValue
URLThe orchestrator's URL (e.g., http://terminals-orchestrator:3000)
API KeyThe orchestrator's TERMINALS_API_KEY
Policy IDThe policy name you created (e.g., data-science)

When you save, Open WebUI routes all requests for this connection through /p/data-science/... on the orchestrator.

2. Restrict access with groupsโ€‹

Each terminal connection supports access grants that control which users or groups can see it. This lets you offer different policies to different teams:

[
  {
    "url": "http://orchestrator:3000",
    "key": "sk-...",
    "policy_id": "development",
    "config": {
      "access_grants": [
        { "principal_type": "group", "principal_id": "engineering", "permission": "read" }
      ]
    }
  },
  {
    "url": "http://orchestrator:3000",
    "key": "sk-...",
    "policy_id": "data-science",
    "config": {
      "access_grants": [
        { "principal_type": "group", "principal_id": "data-team", "permission": "read" }
      ]
    }
  }
]

In this example, the engineering group sees only the development terminal, while the data team sees only the data-science terminal. A user who belongs to both groups would see both.


Global Resource Limitsโ€‹

Administrators can set global limits on the orchestrator that clamp policy values, preventing any policy from exceeding the allowed maximums. These are set as environment variables on the orchestrator itself:

Environment variableExampleDescription
TERMINALS_MAX_CPU8Maximum CPU any policy can request. Policies requesting more are silently clamped to this value.
TERMINALS_MAX_MEMORY32GiMaximum memory any policy can request
TERMINALS_MAX_STORAGE100GiMaximum persistent storage any policy can request
TERMINALS_ALLOWED_IMAGESghcr.io/open-webui/*,gcr.io/my-org/*Comma-separated glob patterns. If set, a policy's image must match at least one pattern or the request is rejected with HTTP 400.

These limits are enforced at policy creation and update time. If a policy's cpu_limit is "16" but TERMINALS_MAX_CPU is "8", the stored value is silently clamped to "8".

tip

Global resource limits give platform administrators a safety net. They can delegate policy creation to team leads while ensuring no single policy can consume an unreasonable amount of cluster resources.


The "default" policyโ€‹

If you haven't created any policies, you don't need to. The orchestrator works out of the box using its global environment variables as the effective default:

SettingEnvironment variable
ImageTERMINALS_IMAGE
Idle timeoutTERMINALS_IDLE_TIMEOUT_MINUTES
Storage modeTERMINALS_KUBERNETES_STORAGE_MODE

This zero-config fallback applies when a terminal connection in Open WebUI has no policy_id set (or the orchestrator receives a request without a /p/ prefix). No database entry is needed; it's equivalent to a single-policy deployment.

If you later create a policy named default in the database, its fields are merged with the global settings (policy values take precedence).


API reference (for programmatic access)

All endpoints are prefixed with /api/v1 on the orchestrator and require the Authorization: Bearer {TERMINALS_API_KEY} header.

MethodEndpointDescription
GET/policiesList all policies
POST/policiesCreate a new policy (body: { "id": "...", "data": { ... } }). Returns 409 if it already exists.
GET/policies/{policy_id}Get a single policy
PUT/policies/{policy_id}Create or update a policy (body: PolicyData fields)
DELETE/policies/{policy_id}Delete a policy

Request body: PolicyDataโ€‹

{
  "image": "ghcr.io/open-webui/open-terminal:latest",
  "cpu_limit": "4",
  "memory_limit": "16Gi",
  "storage": "20Gi",
  "storage_mode": "per-user",
  "env": { "KEY": "value" },
  "idle_timeout_minutes": 60
}

All fields are optional. Omitted fields inherit from the orchestrator's global defaults.

Response body: PolicyResponseโ€‹

{
  "id": "data-science",
  "data": {
    "image": "ghcr.io/open-webui/open-terminal:latest",
    "cpu_limit": "4",
    "memory_limit": "16Gi",
    "storage": "20Gi",
    "env": { "OPEN_TERMINAL_ALLOWED_DOMAINS": "*.pypi.org" },
    "idle_timeout_minutes": 60
  },
  "created_at": "2025-06-01T12:00:00",
  "updated_at": "2025-06-01T12:00:00"
}

Example: multi-team setupโ€‹

A company with three teams (Engineering, Data Science, and Interns) wants different terminal environments.

1. Create policies in Open WebUIโ€‹

In the admin panel under Settings โ†’ Connections โ†’ Open Terminal, create three policies:

PolicyImageCPUMemoryStorageIdle timeout
engineeringDefault24Gi10Gi120 min
data-scienceCustom data science image832Gi50Gi60 min
internDefault11GiNone15 min

2. Create terminal connectionsโ€‹

Add three connections, each pointing to the same orchestrator URL but with different policy_id values: engineering, data-science, and intern.

3. Assign groupsโ€‹

Use access grants on each connection to restrict visibility:

  • Engineering connection โ†’ engineering group
  • Data Science connection โ†’ data-science group
  • Intern connection โ†’ interns group

Users in the engineering group see only the Engineering terminal. Data scientists see only theirs. Interns get limited resources with auto-cleanup after 15 minutes of inactivity.

This content is for informational purposes only and does not constitute a warranty, guarantee, or contractual commitment. Open WebUI is provided "as is." See your license for applicable terms.