Skip to content
Web terminal A real root shell to any server in your fleet — multi-session, resumable, and recorded for audit.

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.

  1. Open Terminal from the sidebar (or expand the bottom Terminal dock and click + New session).
  2. 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.
  3. 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.
  4. The tab connects and drops you at a coloured root prompt. Type away — vim, top, sudo, Ctrl-C and interactive TUIs all work.
  • 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.

The terminal is a real PTY relayed over the same channel everything else uses — your browser never talks to the box directly:

  1. 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.
  2. 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.
  3. Spawn the shell.
    • Managed servers: the broker relays pty.* frames over the box’s existing agent WebSocket. The agent spawns /bin/bash -i with a colour rcfile (so the prompt and ls/grep colours 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.
  4. Record + bound. Every session is written to an asciinema .cast recording 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.

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.
  • Managed shells need Pro or higher. On Free/Plus, the ticket for a managed server is refused with a tier_required error. 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.