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 saves the API key and backend host to
/etc/vsay/agent.yaml. - It installs itself as a systemd service so it survives reboots.
- It opens an outbound TLS connection to the backend and presents the API key on the connection.
From this point on, that one API key is the agent's credential — no SSH key to leak, and nothing else to provision per machine. (Community authenticates the agent with an API key over server-verified TLS; Enterprise Edition adds full client-certificate mTLS issued from a private CA — see the Enterprise how-it-works page.)
2. Establishing the tunnel
On every start (and every reconnect), the agent:
- Loads its saved API key and backend host from config.
- Opens an outbound gRPC connection to the backend over TLS — the agent verifies the backend's certificate, then presents its API key, which the backend checks before accepting the stream.
- 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. Connecting to a machine
When you click Connect on a machine in the dashboard (or run vsay-shell-cli connect <machine>, or open it from the VSCode extension), the backend runs the request through a short verification chain:
- JWT validated — is this a real, currently-authenticated user? (Community Edition issues its own JWT on login, backed by bcrypt-hashed credentials — no external identity provider required.)
- Agent located — is the target machine's gRPC tunnel currently online?
- Session bridged — your browser WebSocket is connected to the machine's gRPC stream, creating a live pipe between the two.
- Commands recorded — each command you run is appended to that machine's command history with a timestamp.
If any one of these fails — expired token, offline machine — the connection is refused.
Community Edition is single-account and single-machine-owner by design: there's no team/role model, no per-machine access grants, no session (keystroke-level) recording, and no audit-log dashboard — just the command list above. Multi-user RBAC, full session recording, audit logs, real-time monitoring, and multi-tenancy (multiple isolated companies under one Super Admin) are available in the Enterprise Edition.
Why This Design Matters
- One key, not many — a single API key authenticates every agent on your account, and can be regenerated in one place if it's ever exposed.
- No network exposure — because the agent only calls out, there is no listening port on any managed machine for an attacker to find.
- Simple by default — Community keeps the flow to four steps: sign in, add a machine, connect, check history. No roles or audit tooling to configure.
For the underlying component diagram and port layout, see Architecture.