# Web Terminal

> Access a full shell on your servers directly from the browser.

URL: https://docs.serverbee.app/en/docs/terminal

ServerBee includes a built-in web terminal that gives administrators direct shell access to any connected server through the browser. No SSH client needed -- just click and type.

## How It Works [#how-it-works]

The web terminal uses a three-hop WebSocket relay, with the server acting as a proxy between the browser and the agent:

```
Browser (xterm.js)  <--WebSocket-->  Server (proxy)  <--WebSocket-->  Agent (PTY)
```

1. The browser opens a WebSocket connection to the server at `/api/ws/terminal/{server_id}`
2. The server authenticates the user (session cookie or API key) and verifies the admin role
3. The server sends a `TerminalOpen` command to the agent over its existing WebSocket connection
4. The agent spawns a PTY (pseudo-terminal) process via the `portable-pty` library, running the system's default shell
5. Input from the browser is forwarded through the server to the agent's PTY, and output flows back along the same path

The shell process runs entirely on the agent machine. Terminal payloads are relayed over WebSocket.

## Usage [#usage]

1. Sign in to the ServerBee dashboard
2. Open the server list and select the target server
3. On the server detail page, click the **Terminal** button (available only for online servers)
4. Once the connection is established, you have a full interactive shell in the browser

<Callout type="warn">
  The web terminal is restricted to the **admin** role. Non-admin (member) users cannot access the terminal and receive a 403 Forbidden response when attempting to open a session.
</Callout>

## Features [#features]

### Full Shell Experience [#full-shell-experience]

* Supports standard shells (bash, zsh, etc., depending on the agent host's default shell)
* Tab completion, command history, and keyboard shortcuts
* Interactive programs such as `vim`, `top`, and `htop`
* Color output and ANSI escape sequences

### Automatic Resizing [#automatic-resizing]

The terminal window adapts to the browser window automatically. When you resize the browser, the terminal's rows and columns are synced to the remote PTY so the display always renders correctly.

### Tokyo Night Theme [#tokyo-night-theme]

The web terminal uses the Tokyo Night color scheme to match ServerBee's dark theme.

### Multiple Sessions [#multiple-sessions]

You can open multiple terminal sessions to the same server simultaneously, making it easy to run different tasks in different tabs.

## Authentication and Access Control [#authentication-and-access-control]

<Callout type="warn">
  The web terminal also requires the **terminal** capability (`CAP_TERMINAL`), which is off by default. It must be enabled on the agent host — add `terminal` to the agent's `[capabilities]` allow list (or pass `--allow-cap terminal`) and restart the agent. Capabilities are agent-owned; the server cannot enable them. If the capability is off, the WebSocket upgrade is rejected with 403 Forbidden. See [Capabilities](/en/docs/capabilities).
</Callout>

Authentication uses the same mechanisms as the REST API:

* **Session cookie** -- sent automatically by the browser after login
* **API key** -- sent via the `X-API-Key` header (useful for programmatic access)

The server validates the user's identity and role before upgrading the connection to a WebSocket.

## Session Limits [#session-limits]

To prevent resource exhaustion, the following limits are enforced:

| Limit                                           | Value      |
| ----------------------------------------------- | ---------- |
| Maximum concurrent terminal sessions per server | 3          |
| Idle timeout                                    | 10 minutes |
| Maximum message size                            | 1 MB       |
| Access                                          | Admin only |

### Idle Timeout [#idle-timeout]

If no input is received from the browser for 10 minutes, the session is closed automatically: the browser receives a timeout error and the agent-side PTY process is terminated. Any input, including resize events, resets the idle timer.

## Terminal Protocol [#terminal-protocol]

The browser and server exchange JSON control messages.

### Browser to Server [#browser-to-server]

**Input** -- Send keystrokes to the shell:

```json
{ "type": "input", "data": "bHM=" }
```

The `data` field contains base64-encoded input.

**Resize** -- Notify the terminal of a window size change:

```json
{ "type": "resize", "rows": 40, "cols": 120 }
```

### Server to Browser [#server-to-browser]

**Session established:**

```json
{ "type": "session", "session_id": "uuid-here" }
```

**Terminal started:**

```json
{ "type": "started" }
```

**Terminal output:**

```json
{ "type": "output", "data": "base64-encoded-output" }
```

**Error:**

```json
{ "type": "error", "error": "Session timed out due to inactivity" }
```

## Session Lifecycle [#session-lifecycle]

1. **Open** -- Browser connects, server assigns a `session_id` and tells the agent to create a PTY
2. **Active** -- Input flows browser-to-agent, output flows agent-to-browser
3. **Close** -- Triggered by any of:
   * User closes the terminal panel
   * Browser WebSocket disconnects
   * Idle timeout (10 minutes)
   * Agent disconnects
   * Server sends `TerminalClose` to the agent

On close, the server sends a `TerminalClose` message to the agent, which terminates the PTY process, and the session is unregistered from the agent manager.

## Security [#security]

### PTY Run-As User [#pty-run-as-user]

The PTY process runs as the system user the agent runs as. The install script configures the agent as a systemd service running as `root` by default, so terminal sessions also run with root privileges.

If this is a concern, run the agent under a dedicated, less-privileged user via the systemd `User=` directive:

```ini title="serverbee-agent.service"
[Service]
User=serverbee
Group=serverbee
ExecStart=/usr/local/bin/serverbee-agent
```

<Callout type="warn">
  Running the agent as a non-root user limits the user's permissions in the terminal and may restrict some system-metric collection (such as TCP/UDP connection counts). ICMP ping probes additionally require the `CAP_NET_RAW` capability.
</Callout>

### Audit Logging [#audit-logging]

Terminal connect and disconnect events are written to the audit log. Administrators can review all session access under Settings → Audit Logs, including the operator's username, target server, connect/disconnect times, and source IP address.

### Transport Encryption [#transport-encryption]

In production, always serve the terminal behind an HTTPS reverse proxy. Unencrypted WebSocket connections can expose terminal input and output to eavesdropping.

## Troubleshooting [#troubleshooting]

### "Agent is offline" [#agent-is-offline]

The terminal requires the target server's agent to be connected. If the agent is offline, the WebSocket upgrade is rejected and an error is shown.

### Connection drops frequently [#connection-drops-frequently]

Behind a reverse proxy, ensure WebSocket connections are forwarded correctly and that read/write timeouts are set to at least 86400 seconds (24 hours). See the [Server Setup](/en/docs/server) guide for an nginx example.

### Terminal is slow or laggy [#terminal-is-slow-or-laggy]

Terminal data is relayed through the central server. If the server is geographically distant from the browser or the agent, you may notice latency -- this is inherent to the relay architecture. For latency-sensitive work, use direct SSH access instead.

<Cards>
  <Card title="Server Setup" href="/en/docs/server" />

  <Card title="Architecture" href="/en/docs/architecture" />

  <Card title="Deployment" href="/en/docs/deployment" />
</Cards>
