Web terminal
The Terminal (/terminal) gives you a real, interactive root shell to any
server in your fleet, right in the browser — no SSH client, no key juggling. It’s
a full-screen workspace with tabs, split columns and a persistent bottom dock, so
you can keep several shells open across different boxes at once. Opening a shell on
a managed (agent) server needs the Pro plan or higher and an org
admin/operator role; agentless (SSH) boxes are owner-only and have no tier
gate.
Open a shell, step by step
Section titled “Open a shell, step by step”- Open Terminal from the sidebar (or expand the bottom Terminal dock and click + New session).
- In the picker, search for a server and click it. Managed servers lead with their IP; offline or suspended boxes are listed but greyed out — a live agent is required to open a shell.
- To reach an agentless (SSH) box, unlock your vault first (the picker shows an Unlock SSH boxes row while it’s locked). Once unlocked, pick the box — MZPanel decrypts its stored SSH credential in your browser and opens the shell with it.
- The tab connects and drops you at a coloured root prompt. Type away —
vim,top,sudo,Ctrl-Cand interactive TUIs all work.
What else you can do
Section titled “What else you can do”- Multiple tabs — click + New session in a column to open more shells; each tab is an independent session with its own connection dot.
- Split layout — the Split layout button adds a second (and third) column side by side, each with its own tabs. Drag the divider to resize.
- Reconnect / Clear — the toolbar’s Reconnect re-dials a dropped session; Clear wipes the on-screen scrollback.
- Minimize to dock — leaving the page (or the Minimize button) drops your
sessions into the persistent bottom dock instead of closing them; they keep
running. Open full screen from the dock brings them back to
/terminal. - Claim a session from another tab — a shell you left running in a different browser tab shows as a dashed ghost tab; click it to pull it into the current tab. (Host shells can move between tabs; SSH/container shells can’t.)
- Saved commands — the Saved commands rail (right side) is a per-user library of reusable snippets in folders: click one to drop it at the prompt, or ▶ to run it.
- Close — close a single tab with its ✕, or Close all sessions from the dock header.
How it works
Section titled “How it works”The terminal is a real PTY relayed over the same channel everything else uses — your browser never talks to the box directly:
- Mint a ticket. Clicking a server calls
POST /v1/servers/:id/terminal/ticket. The API checks your role (admin/operator or super-admin), the plan (Pro/Max for managed servers), and that the agent is online, then returns a single-use ticket (30-second TTL) plus the WebSocket URL. - Upgrade to a stream. The browser dials that WebSocket
(
/v1/servers/:id/terminal?ticket=…). A broker on the control plane consumes the ticket, pins the request Origin, and opens the session. Keystrokes travel as raw binary frames; PTY output comes back as binary — control messages (resize) are small JSON frames. - Spawn the shell.
- Managed servers: the broker relays
pty.*frames over the box’s existing agent WebSocket. The agent spawns/bin/bash -iwith a colour rcfile (so the prompt andls/grepcolours look the same on every box) under a clean root environment. - Agentless (SSH) boxes: the broker opens an SSH PTY from the control plane using the transient, browser-decrypted secret carried in the ticket — no agent involved.
- Managed servers: the broker relays
- Record + bound. Every session is written to an asciinema
.castrecording for audit. Sessions auto-close after 10 minutes idle or 60 minutes total.
State lives in the broker’s memory, not the database: it tracks the live sessions,
the audit records (terminal.open / terminal.resume / terminal.close), and the
recordings on disk. Your tab layout and saved commands are stored locally in the
browser.
API & automation
Section titled “API & automation”This is an account-level, per-server tool rather than something the on-box mz CLI
drives — so there’s no mz terminal command. Two things worth knowing:
- Inside the shell you’re just root on the box, so you can run
mz …directly for everything the dashboard does. See The mz CLI and the command catalog. - Programmatic access goes through the ticket endpoint
(
POST /v1/servers/:id/terminal/ticket→ WebSocket upgrade). See the Control plane API.
Gotchas & troubleshooting
Section titled “Gotchas & troubleshooting”- Managed shells need Pro or higher. On Free/Plus, the ticket for a managed
server is refused with a
tier_requirederror. Agentless SSH boxes have no tier gate but are owner-only. - Offline or suspended servers can’t be opened. A shell needs a live agent, so
those rows show in the picker but are greyed out (
agent_offline/suspended). - Agentless boxes require the vault unlocked. While the vault is locked the picker only offers Unlock SSH boxes; unlocking decrypts credentials in your browser. The terminal is the one place agentless (“Lite”) boxes are usable — they have no Sites/PHP/Backup sections.
- Sessions time out. Idle for 10 minutes or open for 60 minutes and the session is closed automatically — reopen a fresh one. A brief network blip is fine (90s resume grace) for managed shells only.
- Leaving the page doesn’t close your shells. They move to the bottom dock and keep running (and keep being billed against the idle/max timers). Use Close all sessions in the dock header when you’re done.
- Saved commands live in this browser. The snippet library is stored locally, so it doesn’t yet sync across devices or teammates.
- Every session is recorded. Sessions are captured to an audit recording on the control plane. There’s no in-app playback UI yet, so recordings are for audit retention rather than self-service review.
Related
Section titled “Related”- Servers — your fleet, and where agentless boxes are added.
- The mz CLI — the engine you drive once you’re at a prompt.
- Security model — auth, tickets and the trust boundary.
- Control plane API — the ticket + WebSocket surface.