Skip to main content

Terminals (Orchestrator)

Terminals is an enterprise orchestration layer for Open Terminal that provisions a fully isolated terminal container for every user. Instead of sharing a single container, each person gets their own, complete with separate files, processes, resource limits, and network isolation.

Quick navigation

How it works

The orchestrator sits between Open WebUI and the Open Terminal instances:

  1. A user activates a terminal in Open WebUI.
  2. Open WebUI proxies the request to the orchestrator, a service that manages the lifecycle of terminal containers.
  3. The orchestrator provisions a personal Open Terminal container for that user (or reconnects to an existing one).
  4. All traffic is proxied through the orchestrator. The user never connects to their container directly.
  5. Idle containers are automatically cleaned up after a configurable timeout. Data optionally persists across sessions.

The orchestrator also exposes the same OpenAPI-based tool interface as Open Terminal, so the AI can execute commands, read files, and run code, all scoped to the requesting user's container.


Deployment

Prerequisites

Quick start with Docker Compose

This Compose file deploys Open WebUI and the Terminals orchestrator together.

services:
  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    ports:
      - "3000:8080"
    environment:
      - >-
        TERMINAL_SERVER_CONNECTIONS=[{
          "id": "terminals",
          "name": "Terminals",
          "enabled": true,
          "url": "http://terminals:3000",
          "key": "${TERMINALS_API_KEY}",
          "auth_type": "bearer",
          "config": {
            "access_grants": [{
              "principal_type": "user",
              "principal_id": "*",
              "permission": "read"
            }]
          }
        }]
    volumes:
      - open-webui:/app/backend/data
    networks:
      - webui
    depends_on:
      - terminals

  terminals:
    image: ghcr.io/open-webui/terminals:latest
    environment:
      - TERMINALS_BACKEND=docker
      - TERMINALS_API_KEY=${TERMINALS_API_KEY}
      - TERMINALS_IMAGE=ghcr.io/open-webui/open-terminal:latest
      - TERMINALS_NETWORK=open-webui-network
      - TERMINALS_IDLE_TIMEOUT_MINUTES=30
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - terminals-data:/app/data
    networks:
      - webui

volumes:
  open-webui:
  terminals-data:

networks:
  webui:
    name: open-webui-network

Set the shared API key in a .env file next to your Compose file:

TERMINALS_API_KEY=change-me-to-a-strong-random-value

Then start everything:

docker compose up -d

Open WebUI will be available at http://localhost:3000. When any user activates a terminal, the orchestrator provisions their personal container automatically.

Docker socket access

The orchestrator needs access to the Docker socket (/var/run/docker.sock) to manage containers. For production, use a Docker socket proxy like Tecnativa/docker-socket-proxy to restrict the API calls it can make.


Configuration reference
VariableDefaultDescription
TERMINALS_BACKENDdockerBackend type. Set to docker for this deployment mode.
TERMINALS_API_KEY(empty)Shared secret for authenticating requests from Open WebUI. Required.
TERMINALS_IMAGEghcr.io/open-webui/open-terminal:latestDefault container image for user terminals.
TERMINALS_PORT3000Port the orchestrator listens on.
TERMINALS_HOST0.0.0.0Address the orchestrator binds to.
TERMINALS_NETWORK(empty)Docker network for user containers. When set, containers communicate by name.
TERMINALS_DOCKER_HOST127.0.0.1Address for published container ports. Only relevant without TERMINALS_NETWORK.
TERMINALS_DATA_DIRdata/terminalsHost directory for per-user workspace data.
TERMINALS_IDLE_TIMEOUT_MINUTES0 (disabled)Minutes of inactivity before a container is stopped. Set to 30 for typical usage.
TERMINALS_MAX_CPU(empty)CPU limit for user containers (e.g., 2).
TERMINALS_MAX_MEMORY(empty)Memory limit for user containers (e.g., 4Gi).
TERMINALS_OPEN_WEBUI_URL(empty)If set, validates incoming JWTs against this Open WebUI instance instead of using TERMINALS_API_KEY.

Container lifecycle details

Naming. Containers are named terminals-{policy_id}-{user_id}, making them easy to filter with docker ps --filter "label=managed-by=terminals".

Health checks. After creating a container, the orchestrator polls its /health endpoint until it returns HTTP 200 (up to 15 seconds). Only then does it start proxying traffic.

Reconciliation. If the orchestrator restarts, it rediscovers existing running containers by their labels and recovers their API keys from the container configuration. This prevents duplicate containers from being created.

Conflict handling. If a container with the same name already exists (e.g., from a previous failed cleanup), the orchestrator force-removes the old container and retries up to 3 times.


Limitations

  • Single host. All user containers run on one Docker host. For high availability or larger teams, use the Kubernetes Operator backend.
  • No built-in HA. If the orchestrator goes down, active terminal sessions are interrupted (though containers keep running and are reconciled on restart).
  • Docker socket required. The orchestrator needs access to the Docker socket to manage containers.

Authentication

The orchestrator supports three authentication modes:

ModeWhen to useHow to configure
Open WebUI JWTProduction. The orchestrator validates tokens against your Open WebUI instance.Set TERMINALS_OPEN_WEBUI_URL on the orchestrator to your Open WebUI URL.
Shared API keyStandard. Open WebUI includes a shared secret in every request.Set TERMINALS_API_KEY to the same value on both Open WebUI and the orchestrator.
OpenDevelopment only. No authentication. Do not use in production.Leave both TERMINALS_OPEN_WEBUI_URL and TERMINALS_API_KEY unset.

When deployed via Docker Compose or Helm, the shared API key is configured automatically between Open WebUI and the orchestrator.


Troubleshooting

Terminal won't start

  1. Check orchestrator logs. The orchestrator logs the full provisioning flow, including image pull and container creation. Look for errors related to image availability or resource limits.
  2. Verify the API key. Ensure TERMINALS_API_KEY matches between Open WebUI and the orchestrator. A mismatch causes silent auth failures.
  3. Check image pull access. If using a private container registry, make sure the orchestrator (Docker) or cluster (Kubernetes) has pull credentials configured.

Authentication failures

  • If using JWT mode, confirm TERMINALS_OPEN_WEBUI_URL points to a reachable Open WebUI instance.
  • If using API key mode, confirm the key is set identically on both sides. Check for extra whitespace or newlines.
  • Check the orchestrator logs for 401 or 403 responses.

Container is reaped too quickly

Increase TERMINALS_IDLE_TIMEOUT_MINUTES (or idle_timeout_minutes in a policy). The default is 0 (disabled), but if set too low, containers may be cleaned up while users are still working. A value of 30 is typical.

Connection refused

  • Docker: ensure TERMINALS_NETWORK is set so containers can communicate by name. Without it, containers use published ports and the TERMINALS_DOCKER_HOST address must be reachable.
  • Kubernetes: verify the orchestrator Service is accessible from the Open WebUI Pod. Run kubectl get svc -n open-webui to confirm the service exists.

Further reading


License

Terminals requires an Open WebUI Enterprise License for production use. See the Terminals repository for details.

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.