vHaaS Agent
The vHaaS Agent (vhaas-agent) is the software you install on a machine to connect your
hardware setup to the vHaaS web service. Once installed, it registers the machine with vHaaS
and keeps it online through a secure, outbound-only connection — no inbound ports are opened.
Renamed from vehaas-agent
The command, its configuration directory, its environment variables and its service were
renamed from vehaas to vhaas. This page documents the current names. The previous ones
are still accepted so existing scripts and automation keep working, and using one logs a
deprecation warning to standard error telling you the replacement. Two names deliberately
keep their original spelling: the Chocolatey package ID and the rabbitmq.vhost default —
both are noted where they appear.
Requirements
- Operating system — Windows or Linux. The agent ships as a Chocolatey package for Windows and as
.deb/.rpmpackages for Linux (amd64 and arm64). - TPM 2.0 — the agent binds its identity to the host's TPM. Devices without a hardware TPM (for example a Raspberry Pi used as a bench device) need an additional software-TPM package; see vHaaS Agent Setup.
- Privileges —
setupand the service require administrator rights on Windows andsudoon Linux. - Outbound network access — see Network requirements. No inbound ports are opened.
What is a TPM?
A TPM (Trusted Platform Module) is a security chip built into most modern PCs and laptops. It can generate and store private keys internally and never releases them — you can ask it to sign something, but you cannot read the key back out.
That is why the agent uses it: the machine's vHaaS identity is a key pair created inside the TPM, so the identity cannot be copied to another machine even by someone with full access to the disk. See Registration and identity.
Most business-class machines from roughly 2016 onward have one, and it is required for Windows 11. A virtual machine may expose a vTPM from its hypervisor, which works the same way. Small bench devices such as a Raspberry Pi usually have no TPM at all and need the software-TPM package instead.
Commands
All commands accept --config-file (-c) and the --config-<key> overrides described under
Configuration. Errors go to standard error, and each failure class has a
distinct exit code.
setup
Registers the machine with vHaaS. Run once per machine, as administrator or with sudo.
setup initializes the TPM, sends the resulting public keys to the vHaaS proxy, writes the
returned virtual-machine ID into the configuration file as rabbitmq.client-id, configures the
Cloudflare tunnel when the machine was provisioned with one, then switches the agent service to
automatic start and starts it.
| Flag | Short | Description |
|---|---|---|
--registration-token |
-r |
One-time registration token (vhaas_reg_...). Also read from VHAAS_REGISTRATION_TOKEN. |
--non-interactive |
-N |
Never prompt. Fails immediately if no token was supplied, instead of waiting for input. |
--force |
-F |
Re-initialize the TPM even if it already holds valid state, and ignore a persisted registration. |
--url |
-u |
Override vhaas-proxy.url and write it back to the configuration file. Use this to supply the proxy URL on a machine that has no configuration yet. |
--config-file |
-c |
Path to the configuration file. |
Without --registration-token and without --non-interactive, setup prompts for the token.
After a successful run it asks whether to reboot (up to three attempts); --non-interactive
skips that prompt.
The registration token is single-use and expires after one hour
A token can be redeemed once. If it expires or is consumed, obtain a new one — see Re-registering a machine.
run
Runs the agent in the foreground. The installed service does this for you; run it manually only to debug.
| Flag | Short | Description |
|---|---|---|
--context-mode |
-M |
system (default) or user. |
--config-file |
-c |
Path to the configuration file. |
On Windows the agent runs in both modes: the vhaas-agent service runs
run --context-mode system, and a second, per-user process runs run --context-mode user.
Auto-update and the metrics exporter run only in system mode.
The per-user process starts when a user signs in, from an autostart entry the installer writes
to HKCU\Software\Microsoft\Windows\CurrentVersion\Run (value name vhaas-agent-user). It runs
with that user's permissions and inside their desktop session, which is what lets it handle
interactive work such as desktop notifications.
This is a per-user autostart entry, not a logon script
It uses the same Run-key mechanism any desktop application uses to start itself at
sign-in. No Windows logon script, Group Policy object, or Active Directory configuration is
involved, and there is nothing to deploy centrally — installing the agent is enough.
run requires rabbitmq.client-id, rabbitmq.url, and vhaas-proxy.url. If any is missing it
exits with code 30 before connecting.
version
Prints the agent version. Takes no flags.
config show
Prints the effective configuration — configuration file, environment variables, flags, and
defaults merged — in the configuration file's own key layout, so the output can be pasted back
into config.yaml.
Secrets are printed in clear text
config show prints tunnel.token unredacted. Do not paste its output into tickets or chat.
config set
Persists configuration values without re-registering or touching the TPM. Only the
--config-<key> flags you pass explicitly are written; environment variables and defaults are
not. Requires --config-file.
vhaas-agent config set --config-file /usr/local/etc/vhaas-agent/config.yaml \
--config-vhaas-proxy-url https://vhaas.vector.cloud
Comments and key order in the file are not preserved. Changes take effect after a service restart; the command prints the restart command for your platform.
doctor
Runs health checks and prints a status table. This is the first thing to run when something is wrong — see Troubleshooting.
| Flag | Description |
|---|---|
--lines |
Number of log lines to include. Default 50. |
--json |
Emit the report as JSON instead of a table. |
--verbose |
Include raw detail: TLS certificate information, full log lines, raw service output, and the redacted configuration. |
--config-file |
Path to the configuration file. |
doctor exits 50 if any check fails, so it can gate a scripted health check.
Configuration
File location
/usr/local/etc/vhaas-agent/config.yaml
C:\ProgramData\vhaas-agent\config.yaml
The file is written with 0600 permissions because it holds the Cloudflare connector token.
Where settings come from
Each setting is resolved from the first source that provides it:
- Command-line flag —
--config-<key>, for example--config-logging-level debug - Environment variable —
VHAAS_CONFIG_<KEY>, uppercase with underscores, for exampleVHAAS_CONFIG_LOGGING_LEVEL - Configuration file
- Built-in default
Nested keys flatten with hyphens: logging.level becomes --config-logging-level and
VHAAS_CONFIG_LOGGING_LEVEL.
A missing configuration file is not an error
If the file does not exist, the agent falls back to environment variables, flags, and
defaults. A setup or run that seems to ignore your file is often reading a different
path — check with vhaas-agent config show.
Configuration keys
| Key | Default | Description |
|---|---|---|
rabbitmq.url |
— (required) | MQTT broker WebSocket URL. Must be ws:// or wss:// with a host, for example wss://vhaas.vector.cloud/mqtt. |
rabbitmq.client-id |
— (written by setup) |
The virtual-machine ID. Required by run. |
rabbitmq.vhost |
vehaas_agents |
RabbitMQ virtual host. The default keeps its original spelling because it names a virtual host provisioned on the broker — do not change it. |
rabbitmq.tls-skip-verify |
false |
Skip TLS certificate verification. Development only. |
vhaas-proxy.url |
— (required) | vHaaS proxy base URL. Must be http:// or https:// with a host. |
vhaas-proxy.tls-skip-verify |
false |
Skip TLS certificate verification. Development only. |
tunnel.token |
"" |
Cloudflare connector token, written by setup. Secret. |
logging.level |
info |
One of debug, info, warn, error. |
logging.format |
json |
json or text. |
logging.dir |
/var/log/vhaas-agent (Linux), C:\ProgramData\vhaas-agent (Windows) |
Log directory. |
logging.add-source |
false |
Include source locations in log entries. |
autoupdate.enabled |
true |
Enable automatic updates. |
autoupdate.check-interval |
300 |
Seconds between update checks. |
autoupdate.package-manager |
auto-detected | apt, dnf, or choco. |
tpm.url |
"" |
TPM simulator URL, for example tcp://127.0.0.1:2321. Empty means use the hardware TPM. |
metrics-exporter.enabled |
false |
Enable the metrics exporter. |
metrics-exporter.mode |
assembly |
assembly or cluster. |
metrics-exporter.profile |
"" |
Path to a local profile JSON. Used in file mode. |
metrics-exporter.profile-source |
file |
file or pull. pull fetches the assembly profile from vHaaS and follows re-assignment automatically. |
metrics-exporter.profile-refresh-seconds |
900 |
Profile re-pull interval in pull mode. |
metrics-exporter.url |
"" |
Listen URL. Overridden at runtime by the agent's loopback bridge. |
The installed configuration file overrides some built-in defaults
The shipped config.yaml explicitly sets autoupdate.enabled: false,
metrics-exporter.enabled: true, and metrics-exporter.profile-source: pull, which differ
from the built-in defaults above. Run vhaas-agent config show to see what is actually in
effect.
Deprecated keys
These keys still function and log a deprecation warning to standard error, but will be removed in a future release. When both the deprecated key and its replacement are set, the replacement takes precedence.
| Deprecated | Replacement |
|---|---|
rabbitmq.broker-url |
rabbitmq.url |
vhaas-proxy.host + vhaas-proxy.port |
vhaas-proxy.url |
tpm.host + tpm.port |
tpm.url |
metrics-exporter.endpoint |
metrics-exporter.url |
Network requirements
The agent needs outbound access only. No inbound ports are opened.
| Purpose | Protocol / port | If blocked |
|---|---|---|
| Registration, status, metrics, and the MQTT control channel | TCP 443 to the vHaaS platform, including MQTT over WebSocket | The machine cannot register and never appears online. |
| Cloudflare tunnel carrying remote-desktop sessions | UDP/TCP 7844 — see Cloudflare's Tunnel with firewall guide | The machine shows online but sessions fail to open. |
| DNS resolution | UDP/TCP 53 | Registration fails with a host-resolution error. |
| Clock synchronization | NTP UDP 123 | A skewed clock breaks TLS and registration. |
Using an HTTP proxy
The agent honors the standard HTTP_PROXY, HTTPS_PROXY, and NO_PROXY environment variables
for both its HTTPS calls to the vHaaS proxy and its MQTT-over-WebSocket connection.
Automatic updates are the exception: they invoke the system package manager, which uses its own
proxy configuration (apt.conf, dnf.conf, or the Chocolatey configuration) rather than these
variables.
Registration and identity
The machine's identity is bound to its TPM. During setup the agent generates TPM-resident keys
and sends the public keys to vHaaS, which stores them on the virtual-machine record. Every
later connection is signed with those keys, so the identity cannot be copied to another host.
Registration tokens are single-use and valid for one hour. On success setup writes the
returned virtual-machine ID into the configuration file as rabbitmq.client-id; the service uses
it on every subsequent start.
Re-running setup on an already-registered machine does not register again. It first confirms
the stored identity is still accepted, then reuses it. If vHaaS rejects it — because the virtual
machine was deleted or re-enrolled — setup fails with exit code 22 rather than leaving the
agent unable to connect.
Re-registering a machine
Registration is not idempotent: a second registration for a machine that already has keys is
rejected with exit code 11. To move a machine to a fresh identity:
- An administrator clears the stored public keys on the virtual-machine record in vHaaS.
- Obtain a new registration token — the previous one is consumed.
- Re-run setup with
--force:
--force re-initializes the TPM and ignores any persisted registration. Without step 1 it still
fails with exit code 11.
Service and logs
The agent runs as a system service and starts on boot. The package installs the service in a
stopped, manual-start state, because it cannot run before setup has initialized the TPM;
setup switches it to automatic start and starts it.
Managing the service
The service is named vhaas.
Log files
/var/log/vhaas-agent
C:\ProgramData\vhaas-agent
Control the output with logging.level (debug, info, warn, error), logging.format
(json or text), and logging.dir. vhaas-agent doctor tails the log for you — use
--lines to change how much.
Updating
The agent can update itself from the package repository it was installed from.
| Key | Default | Meaning |
|---|---|---|
autoupdate.enabled |
true — but the installed config.yaml sets false |
Whether to check at all. |
autoupdate.check-interval |
300 |
Seconds between checks. |
autoupdate.package-manager |
auto-detected | apt, dnf, or choco. |
Behavior worth knowing:
- The first check happens one full interval after the agent starts, not at startup.
- Checks run only in the
systemcontext — the per-user Windows process never updates. - The update command is launched detached, so the agent does not wait for it and a slow update never blocks the control channel.
- A failed check is logged and the loop continues; it never stops the agent.
To update manually:
The Chocolatey package ID is still vector-vehaas-agent
This is deliberate, not a leftover. Chocolatey has no mechanism for one package to supersede
another under a new ID, so renaming it would leave every existing installation with no
upgrade path. The Linux packages, which do support this, are named vector-vhaas-agent.
An upgrade preserves the machine's identity — the configuration file and TPM state are retained across it.
Uninstalling
Uninstalling removes the agent's identity. The machine must be registered again afterwards.
Use dnf remove on RHEL-family systems. Add vhaas-agent-swtpm if the software-TPM package
was installed. cloudflared is left in place — remove it separately if nothing else needs it.
During removal the agent evicts the TPM key handles that setup created, so a later reinstall
starts from a clean slate. This runs automatically; there is no command to invoke. An upgrade
deliberately does not evict them, which is what preserves the identity.
After uninstalling, delete the virtual-machine entry in vHaaS, or have an administrator clear its keys if you intend to re-register the same machine — see Re-registering a machine.
Troubleshooting
Start with doctor
doctor prints one row per check. Read it top to bottom — a failure in an early row usually
explains every failure below it.
| Row | What it means |
|---|---|
| Agent service / Cloudflared | Whether each service is running. Cloudflared is only required when the machine uses a tunnel; for a direct VM an unhealthy cloudflared is reported as a warning. |
| Config / Setup / Tunnel mode | Whether the configuration file loaded, whether setup has completed (a virtual-machine ID is present), and whether a tunnel token is configured. |
| Backend (HTTPS) | DNS, TCP, TLS, and HTTP reachability of vhaas-proxy.url, broken out so you can see which layer fails. |
| RabbitMQ | The same breakdown for the MQTT WebSocket, ending in the WebSocket upgrade. |
| TPM | Whether the TPM can be opened and its state read. |
| Logs | How many log lines were found, and where. |
skipped does not mean healthy
A connectivity check reports skipped when the setting it needs is absent from the
configuration — the backend check when vhaas-proxy.url is unset, the RabbitMQ check when
rabbitmq.url is unset. It is never skipped because a service is merely down. A skipped row
means fix your configuration, not that the check passed.
Add --verbose for TLS certificate detail and full log lines, or --json to parse the report in
a script. doctor exits 50 when any check fails.
Symptoms
| Symptom | Likely cause | Resolution |
|---|---|---|
setup fails, exit 10 (HTTP 401) |
The registration token is invalid, expired, or already used. Tokens last one hour and work once. | Obtain a new token from the virtual-machine dialog in vHaaS and re-run setup. |
setup fails, exit 11 (HTTP 409) |
The machine already has registered keys. Registration is not idempotent. | See Re-registering a machine. --force alone is not enough — an administrator must clear the stored keys first. |
setup fails, exit 12 (HTTP 422) |
vHaaS rejected the TPM public keys. | Re-run setup --force to re-initialize the TPM, then try again. |
setup fails, exit 13 (HTTP 503) |
The registration service is temporarily unavailable. | Retry. This is the only registration failure worth retrying automatically. |
setup fails, exit 22 |
The stored identity was rejected — the virtual machine was deleted or re-enrolled in vHaaS. | Have an administrator clear the keys, then re-register with a new token and --force. |
setup fails, exit 41 |
Registration succeeded but the configuration could not be written, so the identity was lost locally. | Fix the cause (path, permissions), obtain a new token, and re-run setup --force. A plain re-run fails with 11. |
setup fails, exit 42 |
Registered and persisted, but the Cloudflare tunnel could not be configured — usually cloudflared is missing. |
Install cloudflared, then re-run setup normally. The stored identity is reused, so there is no 11. |
run or the service fails, exit 30 |
A required setting is missing: rabbitmq.client-id, rabbitmq.url, or vhaas-proxy.url. |
Run vhaas-agent config show to see what is in effect. A missing client-id means setup has not completed. |
| Service is inactive and will not start | The service is installed stopped and manual-start; setup normally flips it. If setup warned that it could not start the service, it was never enabled. |
sudo systemctl enable --now vhaas on Linux, Start-Service vhaas-agent on Windows, then check the logs. |
| Machine shows online, but sessions will not open | The Cloudflare tunnel is blocked outbound while the control channel on 443 still works. | Allow UDP/TCP 7844 — see Network requirements. Confirm with the Cloudflared row in doctor. |
| A configuration change had no effect | The value is overridden by an environment variable or a flag, the service was not restarted, or a different file is being read. | vhaas-agent config show prints the effective values. Restart the service after changing the file. |
| The agent is not updating itself | The installed config.yaml ships with autoupdate.enabled: false; the first check is also one interval late, and the per-user Windows process never updates. |
Enable it with config set and restart the service, or update manually — see Updating. |
doctor shows TPM fail |
No TPM 2.0 on the host, or its state is unreadable. | Confirm the host has a TPM 2.0. Bench devices need the software-TPM package. |
Exit codes
When you script the agent — for example from an Ansible playbook — vhaas-agent returns a
distinct exit code for each class of failure, so your automation can branch on the return code
(rc) instead of parsing the error text. These codes are a stable contract and do not change
meaning across releases. Error messages are written to standard error.
| Code | Meaning |
|---|---|
| 0 | Success. |
| 1 | Generic or unexpected error. |
| 10 | Registration token is invalid, expired, or already used. |
| 11 | The virtual machine is already registered. |
| 12 | The TPM public keys were rejected. |
| 13 | The registration service is temporarily unavailable — safe to retry. |
| 20 | TPM error (open, initialize, verify, or read keys). |
| 21 | Registration token missing while running non-interactively. |
| 22 | Cached identity rejected — the VM was deleted or re-enrolled. |
| 30 | Required configuration is missing (proxy or broker settings for run/setup; config set without a config-file path). Nothing has happened yet — fix the configuration and retry. |
| 40 | config set could not write the configuration file. |
| 41 | setup registered the VM but could not persist the configuration (write failed or no config-file path). Do not simply re-run setup — it is rejected as already registered. Recover by fixing the cause, obtaining a new registration token for the VM (the old one is consumed), and re-running setup --force. |
| 42 | setup registered the VM and persisted the configuration, but could not set up the Cloudflare tunnel (cloudflared is not installed, or the service install failed). Safe to retry: re-run setup normally — the saved identity is reused, so there is no already-registered rejection. Once cloudflared is available, the re-run completes. |
| 50 | One or more doctor health checks failed. |
| 80 | Usage error — a bad flag or unknown command. |
Automating with Ansible
Retry only on code 13 (service temporarily unavailable). Treat other non-zero codes as
hard failures that should alert an operator rather than retry — for example 10 (invalid
token), 41 (registered but not persisted), or 42 (registered but the tunnel could not
be set up; once cloudflared is fixed, a plain setup re-run recovers).
- name: Register the vHaaS agent
ansible.builtin.command:
cmd: >-
vhaas-agent setup --non-interactive
--registration-token "{{ vhaas_registration_token }}"
--config-file /etc/vhaas/config.yaml
--config-vhaas-proxy-url "{{ vhaas_proxy_url }}"
--config-rabbitmq-url "{{ vhaas_broker_url }}"
register: vhaas_setup
retries: 5
delay: 30
# Retry only while the registration service is unavailable (rc 13).
until: vhaas_setup.rc != 13
# Any non-zero rc is a failure — including a 13 that persists after all
# retries (a real outage). Inspect vhaas_setup.rc to alert per code,
# e.g. 10 (invalid token), 41 (registered but not persisted), or
# 42 (registered but tunnel not set up; a plain re-run recovers).
failed_when: vhaas_setup.rc != 0