{
    "product": "Cenvero Stratum",
    "generated_at": "2026-10-10T15:54:57+00:00",
    "format": "cenvero-docs-v1",
    "document_count": 1,
    "documents": [
        {
            "slug": "compute/consoles",
            "title": "Consoles",
            "category": "Compute",
            "url": "https://www.stratum.cenvero.com/docs/compute/consoles",
            "headings": [
                {
                    "level": 1,
                    "text": "Consoles"
                },
                {
                    "level": 2,
                    "text": "The serial console on the node"
                },
                {
                    "level": 2,
                    "text": "Consoles over the API"
                },
                {
                    "level": 2,
                    "text": "A machine on another member of a cluster"
                },
                {
                    "level": 2,
                    "text": "Limits and timeouts"
                },
                {
                    "level": 2,
                    "text": "The licence"
                },
                {
                    "level": 2,
                    "text": "Every session is recorded"
                },
                {
                    "level": 2,
                    "text": "See also"
                }
            ],
            "word_count": 1264,
            "markdown": "# Consoles\n\nEvery virtual machine has two consoles, as a physical server would: a **serial\nconsole** (text, what the guest prints on its first serial port) and a\n**graphical console** (its screen, keyboard and mouse). Both work whatever\nstate the guest's network is in — they are how you rescue a machine that has\nlocked itself out.\n\n> Part of [Compute](/docs/compute/overview), in early access. In the browser,\n> the node's [web console](/docs/compute/web-console) opens both consoles for\n> you; this page covers the node's command line and the local API underneath.\n\n## The serial console on the node\n\n```bash\nsudo cenvero-str-ctl vm console vm-3f9a1c2e\n```\n\nYour terminal becomes the machine's serial console. Everything you type goes to\nthe guest, Ctrl+C included; **Ctrl+]** disconnects. Press Enter if the screen\nstays empty — the guest prints its login prompt again.\n\n- One serial session per machine at a time. `--force` takes it over from\n  another Stratum session (that one is closed, and told why); `--force=false`\n  is the same as leaving it out.\n- If another program on the node has the machine's serial console open, the\n  console is refused until that program lets go — and while you are connected,\n  that program is refused. Neither ever silently takes the other's keystrokes.\n- The machine must be running.\n- Input from a pipe or a file instead of your keyboard (`echo … | … vm console`)\n  ends the session at the end of that input.\n- A terminal that stops reading (a suspended job, say) is disconnected once it\n  has left the machine's output unread for 30 seconds, so it cannot hold the\n  serial console.\n- Closing the command with a signal (`kill`, including `kill -INT`) ends the\n  session and puts your terminal back as it was.\n\n## Consoles over the API\n\nThe local API serves both consoles as WebSockets. A browser cannot put a token on\na WebSocket, so you first ask for a **ticket** — single use, valid for 60\nseconds, for one console of one machine:\n\n```bash\ncurl -k -X POST \"$NODE/api/v1/vms/vm-3f9a1c2e/console\" -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" -d '{\"type\":\"vnc\"}'\n```\n\n```json\n{\n  \"ticket\": \"q3J0…\",\n  \"expires_in\": 60,\n  \"path\": \"/api/v1/vms/vm-3f9a1c2e/console/vnc?ticket=q3J0…\",\n  \"type\": \"vnc\"\n}\n```\n\nThen open `wss://<node>:7070` + `path` as a WebSocket:\n\n| `type` | Path | What flows |\n|---|---|---|\n| `vnc` | `…/console/vnc` | The graphical console, as VNC (RFB) in binary frames. A standard noVNC client connects to it unchanged; the `binary` subprotocol is accepted |\n| `serial` | `…/console/serial` | The serial console's bytes. Text or binary frames from you; binary frames back |\n\nScripts may skip the ticket and send the operator token on the upgrade itself\n(`Authorization: Bearer …`), for example with `websocat`. `\"force\": true` in the\nticket request (or `?force=true` with a token) takes the serial console over, as\n`--force` does above; `force` takes `true` or `false`.\n\nA ticket is used up only by the WebSocket connection it was made for. A plain\n`GET` of the path (a browser prefetching a link, a check with `curl`), a request\nthat is not a valid WebSocket handshake, or a page on another site is refused\nwithout touching the ticket, so the real viewer can still use it.\n\n**Who may open one.** An operator token or operator API key. A tenant-scoped key\nopens the consoles of its own tenant's machines with a ticket from\n`POST /api/v1/tenant/{id}/vms/{vmid}/console` (the tenant portal, see\n[API Reference](/docs/api)); it is not accepted on the WebSocket itself, and\nnot while its tenant is suspended. A browser page on another site cannot open a console: the\nWebSocket's origin must be the node itself or one you listed in\n`api_allowed_origins`. Failed attempts count towards the API's lock-out, like\nany other.\n\nThe local API must be enabled on the node (it is off by default — see\n[Installation](/docs/installation)). The serial console on the node's command\nline works without it.\n\n## A machine on another member of a cluster\n\nIn a [cluster](/docs/clustering/overview) (agent 1.0.0-rc.81 or later), any\nmember opens the consoles of every member's machines. Ask the member you are\nconnected to for the ticket, with `/api/v1/nodes/<node id>` in front of the\npath, where `<node id>` is the member the machine runs on:\n\n```bash\ncurl -k -X POST \"$NODE/api/v1/nodes/7c9e6679-7425-40de-944b-e07fc1f90ae7/vms/vm-3f9a1c2e/console\" \\\n  -H \"Authorization: Bearer $TOKEN\" -H \"Content-Type: application/json\" -d '{\"type\":\"vnc\"}'\n```\n\nThe answer's `path` is then\n`/api/v1/nodes/7c9e6679-7425-40de-944b-e07fc1f90ae7/vms/vm-3f9a1c2e/console/vnc?ticket=…`.\nOpen it on the same member you asked, which passes the console on to the\nmachine's node. A console on another member always needs a ticket from that\nsame member, asked for with the same key; a token sent on the WebSocket alone\nis not enough. The member you call needs clustering in its licence, and tenant\nkeys open consoles only on the node that issued them. The machine's node applies\nits own address allowlist (`api_allowed_ips`) to your address: if it does not\naccept it, the ticket and the console are refused with **403**\n`forbidden: source address not allowed`. The same limits apply, and the session\nalso closes when either node leaves the cluster.\n\n## Limits and timeouts\n\n| | |\n|---|---|\n| Sessions per machine | Up to 4 graphical sessions (they share the screen) and 1 serial session |\n| Idle | A session closes after 30 minutes without input from you. On the graphical console only keyboard, mouse and clipboard count as input — an open, forgotten tab does not keep it alive |\n| Ticket | Single use, 60 seconds |\n| Machine stops or is deleted | Its sessions close, with the reason |\n| The key is revoked | A session lasts only as long as the key or token that opened it (the one that asked for the ticket, or the one sent on the WebSocket). Revoking it — or a tenant key expiring — closes the session within a few seconds, and an unused ticket it asked for is refused |\n| Web console sign-out | A session opened from the [web console](/docs/compute/web-console) closes when you sign out or that sign-in ends (idle, 12 hours) |\n| Tenant suspended | A session opened with a tenant's ticket closes within a few seconds of the tenant being suspended or closed, or of the machine no longer being the tenant's |\n| Agent restarts or updates | Sessions close (\"the agent is stopping\"); the machine keeps running. Reconnect once the agent is back |\n\nA session ends with a normal close whose reason says why, in plain words. A\nconsole that cannot be opened is refused with a plain reason; the details are in\nthe agent's log.\n\n## The licence\n\nOpening a console changes nothing on the node, so it is treated like looking at\na machine: it works while the licence is frozen, and on a plan without Compute,\nas long as the machine exists (and runs). Getting a ticket works the same way.\nStarting, stopping and changing machines still need an active licence that\nincludes Compute.\n\n## Every session is recorded\n\nOpening, closing and every refusal are recorded in the node's audit log (who,\nfrom where, which machine and console, how long it was open — see\n[Monitoring](/docs/monitoring)), written to the agent's log as audit entries\n(`audit=true`, with the bytes each way) and published as\n`compute.console_opened` and `compute.console_closed` events, so the\n[event stream](/docs/api) and webhooks carry them.\n\n## See also\n\n- [Lifecycle and restarts](/docs/compute/lifecycle)\n- [API Reference](/docs/api)\n"
        }
    ]
}