How WebXTerm Works
This page walks through the full lifecycle of a WebXTerm connection — from installing the agent on a machine to a user typing a command in the browser — so you can see exactly what happens at each step and why it's secure.
The Core Idea: Agent-Based, Outbound-Only
Traditional remote access (SSH, VPN, bastion hosts) requires inbound access to a machine — you open a port, distribute a key, and hope it's rotated when someone leaves. WebXTerm flips this around.
You install a small daemon called vsay-agent on each machine you want to manage. The agent's only job is to dial out to the WebXTerm backend and hold that connection open. Nothing ever connects into your machine. This means:
- No inbound firewall rules, ever
- Works identically on a laptop behind NAT, a server in a private VPC, or a bare-metal box in a colo
- If the agent process is removed, the machine is simply unreachable — there's no leftover open port to worry about
Step-by-Step: From Install to Session
1. Registering a machine (configure)
An admin runs:
sudo vsay-agent configure --token <API_KEY> --host https://your-instance.com
Behind the scenes:
- The agent downloads the backend's CA certificate.
- It generates its own private key locally (the key never leaves the machine).
- It creates a Certificate Signing Request (CSR) and submits it to the backend along with the API key.
- The backend's private CA signs the CSR and returns a client certificate.
- The agent stores the CA cert, its client cert, and its private key under
/etc/vsay/certs/, and installs itself as a systemd service so it survives reboots.
From this point on, the machine has a durable cryptographic identity — no shared secret, no SSH key to leak or rotate.
2. Establishing the tunnel
On every start (and every reconnect), the agent:
- Loads its certificate and key from disk.
- Opens an outbound gRPC connection to the backend, authenticating with mutual TLS — the agent proves its identity to the backend, and the backend proves its identity to the agent. Neither side trusts the connection until both certificates check out.
- Sends a heartbeat every 30 seconds with live CPU, memory, and disk stats. If heartbeats stop, the backend marks the machine offline automatically.
This tunnel is the only channel between the machine and WebXTerm. All terminal traffic, file operations, and monitoring data flow over it.
3. A user requests access
When someone clicks Connect on a machine in the dashboard (or runs vsay-shell-cli connect <machine>, or opens it from the VSCode extension), the backend runs every request through the same verification chain, in order:
- JWT validated — is this a real, currently-authenticated user?
- RBAC checked — has this specific user been explicitly granted access to this specific machine? (And with which privilege level — sudo or non-sudo?)
- Agent located — is the target machine's gRPC tunnel currently online?
- Session bridged — the user's browser WebSocket is connected to the machine's gRPC stream, creating a live pipe between the two.
- Commands logged — every keystroke and command executed in the session is written to the audit log with the user, machine, timestamp, and exit code.
If any one of these fails — expired token, no grant, offline machine — the connection is refused. There's no fallback path and no way to reach a machine you haven't been explicitly granted.
4. Multi-tenant isolation
All of the above happens inside an organizational boundary. A Super Admin can operate multiple companies from one deployment, but each Company Admin only ever sees their own organization's machines, users, and audit logs — enforced at the database level, not just in the UI. Users under a company can only reach machines their admin has explicitly granted them, at the privilege level (sudo or non-sudo) that grant specifies.
Why This Design Matters
- No key sprawl — certificates are issued and rotated automatically by the platform's own CA; there's nothing for a departing engineer to walk away with.
- No network exposure — because the agent only calls out, there is no listening port on any managed machine for an attacker to find.
- Full accountability — because every session is bridged through the backend (rather than a direct SSH hop), every command is logged centrally, with no client-side step that could be skipped.
- Scales to fleets — the same certificate-issuance and heartbeat model works for one machine or several thousand; there's no per-machine manual key management to fall behind on.
For the underlying component diagram and port layout, see Architecture.