diff --git a/docs/features/open-terminal/advanced/multi-user.md b/docs/features/open-terminal/advanced/multi-user.md index cd4d5dac7a..bfda157d38 100644 --- a/docs/features/open-terminal/advanced/multi-user.md +++ b/docs/features/open-terminal/advanced/multi-user.md @@ -10,7 +10,7 @@ When multiple people on your team need terminal access through Open WebUI, you h | | Single Container | Per-User Containers | | :--- | :--- | :--- | | **How** | One container, separate accounts inside | Each user gets their own container | -| **Isolation** | Separate workspaces inside one shared container | A separate container per user, isolated from each other | +| **Isolation** | Separate workspaces inside one shared container | A separate container per user, with its own files, processes, and resources. On the Docker backend the containers share one network | | **Setup** | One extra setting | Additional orchestration service | | **Best for** | Small teams where everyone is trusted equally | Production, larger teams, untrusted users | | **Included in** | Open Terminal (free) | [Terminals](https://github.com/open-webui/terminals) (enterprise) | @@ -20,7 +20,7 @@ If your Open WebUI instance has **more than one user account** and the same term **Option 1 separates workspaces. It is not a security boundary between users.** Everyone still shares one kernel, one process list, one network namespace and one set of system resources, and provisioning the per-user accounts requires elevated privileges inside that container, so a user who sets out to reach root inside it will get there. Run it where every user on the instance is trusted at the same level. -For deployments with **untrusted users** (open signup, public-facing portals, users who are not trusted with each other's data), use **Option 2 (per-user containers via Terminals)**, which is the option that puts a real boundary between users. Layering `TERMINAL_PROXY_HEADERS` on top of Option 1 restricts what a proxied response can do in the user's browser, and it changes nothing about the shared container itself. +For deployments with **untrusted users** (open signup, public-facing portals, users who are not trusted with each other's data), use **Option 2 (per-user containers via Terminals)** on its Kubernetes backend with a NetworkPolicy, which is the setup that puts a real boundary between users. Layering `TERMINAL_PROXY_HEADERS` on top of Option 1 restricts what a proxied response can do in the user's browser, and it changes nothing about the shared container itself. ::: --- @@ -67,7 +67,7 @@ Each user sees only their own files in the file browser. :::warning Good for small trusted teams, not production This mode gives everyone their own workspace, and they all run inside the same container. Resource pressure (memory, CPU) is shared. The network namespace is shared, so a port one user binds (e.g. `python -m http.server 8080`) is reachable from any other user's shell on that container. The port listing and the port proxy are scoped to the user who owns the port, so the port stays out of other users' file navigators, and reaching it takes a direct request from a shell. The process list is shared, so users can watch each other's running commands. Root inside the container is reachable from any account, because provisioning the accounts needs those privileges in the first place. -Treat every user on one instance as equally trusted, and use **Option 2 (per-user containers)** below when users have to be protected from each other. Layering the [`TERMINAL_PROXY_HEADERS`](/reference/env-configuration#terminal_proxy_headers) configuration on top locks proxied responses into a sandbox CSP in the browser, which is worth doing and does not change what happens inside the container. +Treat every user on one instance as equally trusted, and use **Option 2 (per-user containers)** below, on its Kubernetes backend, when users have to be protected from each other. Layering the [`TERMINAL_PROXY_HEADERS`](/reference/env-configuration#terminal_proxy_headers) configuration on top locks proxied responses into a sandbox CSP in the browser, which is worth doing and does not change what happens inside the container. ::: ```mermaid @@ -96,7 +96,7 @@ flowchart LR ## Option 2: Per-user containers with Terminals -For larger deployments or when you need real isolation, [**Terminals**](../terminals/) gives each user their own container, completely separate from everyone else. +For larger deployments or when you need real isolation, [**Terminals**](../terminals/) gives each user their own container, with files, processes, and resources separate from everyone else's. - **Full isolation**: each user's container is independent with its own files, processes, and resources - **On-demand provisioning**: containers are created when users start a session and cleaned up when idle @@ -104,6 +104,7 @@ For larger deployments or when you need real isolation, [**Terminals**](../termi - **Multiple environments**: different setups for different teams (e.g., data science, development) - **Kubernetes support**: works with Docker, Kubernetes, and k3s - **Scoped workspaces**: optionally give each saved chat or each automation its own workspace instead of one per user, via [Terminal Contexts](/features/open-terminal/terminals/orchestration/contexts) +- **One network on the Docker backend**: every workspace sits on the same Docker network so the orchestrator can reach each one by name, which also lets a workspace reach a port another user's workspace has opened. Files and processes stay separate. For mutually untrusted users, run the Kubernetes backend and add a NetworkPolicy ```mermaid flowchart LR @@ -123,8 +124,8 @@ flowchart LR Two deployment backends are available: -- **[Docker Backend](../terminals/)**: runs on a single Docker host. Best for small-to-medium teams or environments without Kubernetes. -- **[Kubernetes Operator](../terminals/)**: production-grade deployment using a CRD-based operator. Deploys alongside Open WebUI via the Helm chart. +- **[Docker Backend](../terminals/#deployment)**: runs on a single Docker host. Best for small-to-medium teams or environments without Kubernetes. +- **[Kubernetes Operator](../terminals/#deployment)**: production-grade deployment using a CRD-based operator. Deploys alongside Open WebUI via the Helm chart. :::info Enterprise license required Terminals requires an [Open WebUI Enterprise License](https://docs.openwebui.com/enterprise). See the [Terminals repository](https://github.com/open-webui/terminals) for license details. @@ -133,7 +134,7 @@ Terminals requires an [Open WebUI Enterprise License](https://docs.openwebui.com ## Related - [Terminals overview →](../terminals/) -- [Terminals: Docker Backend →](../terminals/) -- [Terminals: Kubernetes Operator →](../terminals/) +- [Terminals: Docker Backend →](../terminals/#deployment) +- [Terminals: Kubernetes Operator →](../terminals/#deployment) - [Security best practices →](./security.md) - [All configuration options →](./configuration.md) diff --git a/docs/features/open-terminal/terminals/orchestration/contexts.md b/docs/features/open-terminal/terminals/orchestration/contexts.md index 708fbf7b85..d47ae59f63 100644 --- a/docs/features/open-terminal/terminals/orchestration/contexts.md +++ b/docs/features/open-terminal/terminals/orchestration/contexts.md @@ -49,8 +49,9 @@ A terminal that is **Off** for chats is not listed in the chat terminal picker, A per chat workspace belongs to a specific conversation, so the conversation has to exist first. It does once the first message has been sent and the chat appears in the sidebar. - In a new conversation that has not been sent yet, the terminal panel and file browser for that terminal are not available. They appear once the chat is saved. -- In a [temporary chat](/features/chat-conversations/chat-features/url-params#8-temporary-chat-sessions), a per chat terminal is not listed in the terminal picker at all. A temporary chat is never saved, so there is nothing for the workspace to belong to. -- Nothing quietly falls back to the shared workspace. Before the chat is saved the terminal is refused, and a model told to use it reports an error naming the terminal. +- In a [temporary chat](/features/chat-conversations/chat-features/url-params#8-temporary-chat-sessions), a per chat terminal has nothing to attach to, because a temporary chat is never saved. The picker drops the terminal once the temporary chat exists. Before its first message the picker still lists it, and a message sent with it selected fails with `Terminal unavailable: Terminal server '' requires a saved chat context`. +- Nothing in the interface quietly falls back to the shared workspace. Before the chat is saved the terminal is refused, and a model told to use it reports an error naming the terminal. +- A request that reaches the proxy with no chat id at all, such as a direct API call, is not scoped to any chat and lands in the shared workspace even when the row is **Per chat**. The Open WebUI interface always sends the chat id. ## Capacity diff --git a/docs/features/open-terminal/terminals/orchestration/environment-variables.md b/docs/features/open-terminal/terminals/orchestration/environment-variables.md index 12a9f57213..dd67652a3f 100644 --- a/docs/features/open-terminal/terminals/orchestration/environment-variables.md +++ b/docs/features/open-terminal/terminals/orchestration/environment-variables.md @@ -44,7 +44,7 @@ Policy env vars are visible to the user inside their terminal. Do not put secret ## Automatically Injected Resource Vars -These are set automatically by the orchestrator from the policy's `cpu_limit` and `memory_limit`, so a system prompt or tool can read the container's resource budget. They are not user-configured. +These are set automatically by the orchestrator from the policy's `cpu_limit` and `memory_limit`, so a system prompt or tool can read the container's resource budget. They are not user-configured. Inside a capped workspace, `nproc` and `free` still report the host's cores and memory, so these variables are the only in-container source of the real limits. | Variable | Purpose | | :--- | :--- | diff --git a/docs/features/open-terminal/terminals/orchestration/policies.md b/docs/features/open-terminal/terminals/orchestration/policies.md index 400ea28894..8dcfbbf95c 100644 --- a/docs/features/open-terminal/terminals/orchestration/policies.md +++ b/docs/features/open-terminal/terminals/orchestration/policies.md @@ -9,7 +9,7 @@ A policy describes what a user's Open Terminal workspace should look like. It co Think of policies as agent workspace profiles. A data team might get Python, notebooks, and larger storage. A training lab might get a locked-down image and scheduled resets. A software team might get Git, build tools, language runtimes, and persistent files. -In Open WebUI, go to **Settings** -> **Admin** -> **Tools** -> **Integrations** -> Open Terminal**, add an orchestrator connection, verify it, then edit the policy fields. +In Open WebUI, go to **Settings > Admin > Integrations**, add an orchestrator connection in the **Open Terminal** section, verify it, then edit the policy fields. ## Policy Fields diff --git a/docs/features/open-terminal/terminals/tab-deployment/Docker.md b/docs/features/open-terminal/terminals/tab-deployment/Docker.md index 7f85e25b11..3261126f85 100644 --- a/docs/features/open-terminal/terminals/tab-deployment/Docker.md +++ b/docs/features/open-terminal/terminals/tab-deployment/Docker.md @@ -108,7 +108,7 @@ The orchestrator needs access to the Docker socket (`/var/run/docker.sock`) to m
Container lifecycle details -**Naming.** Containers are named `terminals-` (where `` is the first 12 hex chars of the SHA-256 of the user ID, for a DNS-safe name), or `terminals--` for non-default policies. They are easy to filter with `docker ps --filter "label=app.kubernetes.io/managed-by=terminals"`. +**Naming.** Containers are named `terminals-` (where `` is the first 12 hex chars of the SHA-256 of the user ID, for a DNS-safe name), or `terminals--` for non-default policies. They are easy to filter with `docker ps --filter "label=app.kubernetes.io/managed-by=terminals"`. One container is also provisioned under the user id `system`, which Open WebUI uses to read a policy's tool list and system prompt, so a row for a user you do not recognize is expected. **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.