Skip to main content

⚡ Open Terminal

info

This page is up-to-date with Open Terminal release version v0.1.10.

Overview

Open Terminal is a lightweight API for running shell commands remotely — with real-time streaming and secure access. When connected to Open WebUI as a Tool, it gives models full shell access, file management, and the ability to execute arbitrary commands in an isolated environment.

Unlike Pyodide (browser-based, limited libraries) or Jupyter (shared environment, no per-user isolation), Open Terminal runs in its own Docker container with full OS-level capabilities. This makes it ideal for tasks that require:

  • Installing and running any software package or language
  • Working with system tools like ffmpeg, pandoc, git, etc.
  • Running multi-step build, analysis, or data processing pipelines
  • Managing files with upload and download support
warning

Open Terminal provides unrestricted shell access to the environment it runs in. In production deployments, always run it inside a Docker container with appropriate resource limits. Never run it on bare metal in a shared or untrusted environment.

Getting Started

docker run -d --name open-terminal --restart unless-stopped -p 8000:8000 -e OPEN_TERMINAL_API_KEY=your-secret-key ghcr.io/open-webui/open-terminal

If no API key is provided, one is auto-generated and printed on startup (docker logs open-terminal).

The Docker image is based on Python 3.12 and comes pre-installed with a rich set of tools:

CategoryIncluded
Core utilitiescoreutils, findutils, grep, sed, gawk, diffutils, patch, less, file, tree, bc
Networkingcurl, wget, net-tools, iputils-ping, dnsutils, netcat, socat, telnet, openssh-client, rsync
Editorsvim, nano
Version controlgit
Build toolsbuild-essential, cmake, make
LanguagesPython 3.12, Perl, Ruby, Lua 5.4
Data processingjq, xmlstarlet, sqlite3
Compressionzip, unzip, tar, gzip, bzip2, xz, zstd, p7zip
Systemprocps, htop, lsof, strace, sysstat, sudo, tmux, screen
Python librariesnumpy, pandas, scipy, scikit-learn, matplotlib, seaborn, plotly, jupyter, ipython, requests, beautifulsoup4, lxml, sqlalchemy, psycopg2, pyyaml, toml, jsonlines, tqdm, rich

Build from Source

docker build -t open-terminal .
docker run -p 8000:8000 open-terminal

pip Install (Bare Metal)

pip install open-terminal
open-terminal run --host 0.0.0.0 --port 8000 --api-key your-secret-key
warning

Running bare metal gives the model shell access to your actual machine. Only use this for local development or testing.

Docker Compose (with Open WebUI)

docker-compose.yml
services:
open-webui:
image: ghcr.io/open-webui/open-webui:latest
container_name: open-webui
ports:
- "3000:8080"
volumes:
- open-webui:/app/backend/data

open-terminal:
image: ghcr.io/open-webui/open-terminal
container_name: open-terminal
ports:
- "8000:8000"
environment:
- OPEN_TERMINAL_API_KEY=your-secret-key
deploy:
resources:
limits:
memory: 2G
cpus: "2.0"

volumes:
open-webui:

Configuration

CLI OptionDefaultEnvironment VariableDescription
--host0.0.0.0Bind address
--port8000Bind port
--api-keyAuto-generatedOPEN_TERMINAL_API_KEYBearer API key for authentication

When no API key is provided, Open Terminal generates a random key using a cryptographically secure token and prints it to the console on startup.

Connecting to Open WebUI

Open Terminal is a FastAPI application and automatically exposes an OpenAPI specification at /openapi.json. This means it works out of the box as an OpenAPI Tool Server — no manual tool creation required.

  • As a User Tool Server: Add it in Settings → Tools to connect directly from your browser. Ideal for personal or local instances.
  • As a Global Tool Server: Add it in Admin Settings → Tools to make it available to all users across the deployment.

For step-by-step instructions with screenshots, see the OpenAPI Tool Server Integration Guide.

API Reference

All endpoints except /health and temporary download/upload links require Bearer token authentication.

Interactive API documentation (Swagger UI) is available at http://localhost:8000/docs when the server is running.

Execute a Command

POST /execute

Runs a shell command and returns the result. Supports pipes, chaining (&&, ||, ;), and redirections.

tip

The /execute endpoint description in the OpenAPI spec automatically includes live system metadata — OS, hostname, current user, default shell, Python version, and working directory. When Open WebUI discovers this tool via the OpenAPI spec, models see this context in the tool description and can adapt their commands accordingly.

Request body:

FieldTypeDefaultDescription
commandstring(required)Shell command to execute
timeoutnumber30Max execution time in seconds. Process is killed if exceeded. Set to null to disable.

Query parameter:

ParameterDefaultDescription
streamfalseIf true, stream output as JSONL instead of waiting for completion

Synchronous response:

curl -X POST http://localhost:8000/execute \
-H "Authorization: Bearer <api-key>" \
-H "Content-Type: application/json" \
-d '{"command": "echo hello"}'
{"exit_code": 0, "stdout": "hello\n", "stderr": ""}

Exit code -1 indicates the command was killed due to timeout.

Streaming response:

curl -X POST "http://localhost:8000/execute?stream=true" \
-H "Authorization: Bearer <api-key>" \
-H "Content-Type: application/json" \
-d '{"command": "for i in 1 2 3; do echo $i; sleep 1; done"}'

Streams as JSONL (application/x-ndjson):

{"type": "stdout", "data": "1\n"}
{"type": "stdout", "data": "2\n"}
{"type": "stdout", "data": "3\n"}
{"type": "exit", "data": 0}

Upload a File

POST /files/upload

Save a file to the container filesystem. Provide either a url to fetch remotely, or send the file directly via multipart form data.

From URL:

curl -X POST "http://localhost:8000/files/upload?url=https://example.com/data.csv&dir=/tmp" \
-H "Authorization: Bearer <api-key>"

Direct upload:

curl -X POST "http://localhost:8000/files/upload?dir=/tmp" \
-H "Authorization: Bearer <api-key>" \
-F "file=@local_file.csv"

Via temporary upload link (no auth needed to upload):

# 1. Generate an upload link
curl -X POST "http://localhost:8000/files/upload/link?dir=/tmp" \
-H "Authorization: Bearer <api-key>"
# → {"url": "http://localhost:8000/files/upload/a1b2c3d4..."}

# 2. Upload to the link (no auth required)
curl -X POST "http://localhost:8000/files/upload/a1b2c3d4..." \
-F "file=@local_file.csv"

Opening a temporary upload link in a browser shows a simple file picker form — useful for manual uploads without curl.

The filename is automatically derived from the uploaded file or the URL.

Download a File

GET /files/download/link

Returns a temporary download URL for a file. The link expires after 5 minutes and requires no authentication to use.

curl "http://localhost:8000/files/download/link?path=/tmp/output.csv" \
-H "Authorization: Bearer <api-key>"
{"url": "http://localhost:8000/files/download/a1b2c3d4..."}

Health Check

GET /health

Returns service status. No authentication required.

{"status": "ok"}

Security Considerations

  • Always use Docker in production. Running Open Terminal on bare metal exposes the host system to any command the model generates.
  • Set an API key. Without one, anyone who can reach the port has full shell access. If you don't provide one, the auto-generated key is printed once at startup — save it.
  • Use resource limits. Apply --memory and --cpus flags in Docker to prevent runaway processes from consuming host resources.
  • Network isolation. Place the Open Terminal container on an internal Docker network that only Open WebUI can reach, rather than exposing it to the public internet.
  • Container is ephemeral. Files inside the container are lost when the container is removed. Mount a volume if you need persistence.

Further Reading