CLI commands & background daemons
NexoVirt is one CodeIgniter application plus a set of php spark sub-commands: some run continuously as
system services, others are one-shot commands driven by cron, and a few are detached workers the panel
starts on its own. The installer sets all of this up, so you normally never run these by hand. This page
documents what is running so you can troubleshoot.
System services
Section titled “System services”The installer installs and enables three systemd units. If one of them is down, the matching part of the panel (live charts, inventory, consoles) stops updating.
| Unit | Runs | Purpose |
|---|---|---|
nexovirt-metrics | spark metrics:collect | Samples guest metrics (default every 5 s) and node metrics (default every 30 s) into the database for the live charts. Cadence and retention are set under Settings → Metrics. |
nexovirt-inventory | spark inventory:collect | Every 5 minutes (inventory.interval), pulls each active host’s nodes, guests, storages and networks into change-only inventory snapshots. Also discovers PBS storages and detects externally made guest state changes. |
nexovirt-console | proxy/console-proxy.php start | The WebSocket proxy that relays browser consoles (xterm.js and noVNC) to Proxmox. It injects the Proxmox auth cookie server-side, so it never reaches the browser. Not a spark command; stop halts it, start -d daemonizes. |
Cron-scheduled commands
Section titled “Cron-scheduled commands”deploy/install-cron.sh writes these into the app user’s crontab, inside a marked block that it replaces
on every run (hand-added entries outside the block are kept). Installs and updates re-run it, so the
schedule always matches the installed version.
| Command | Cadence | What it does |
|---|---|---|
metrics:collect --cron | every minute | Same sampling as the service, as a self-locked cron tick. |
metrics:prune --once | daily, 03:17 | Enforces retention: guest metrics (24 h), node metrics (180 days), inventory history (keeps each resource’s latest row), logs, error events, webhook deliveries, finished provisioning jobs. Also queues the cleanup of expired migration safety copies. |
inventory:collect --once | every 5 minutes | Single inventory pass. |
provision:work --cron | every minute | Drains the provisioning queue: guest create, reinstall, delete and power actions. Required while provision.async=1 (the default). |
migrate:work --cron | every minute | Separate lane for long jobs: cross-host migrations, safety-copy cleanup, failover restores and re-keyed PBS restores. Also drives evacuation, balance and failover runs. |
hooks:flush --once | every minute | Sends pending event webhook deliveries with retries. No-op without configured hooks. |
mail:flush --once | every minute | Sends queued emails over SMTP. A mail failure never breaks the action that queued it. |
crash:flush --once | every minute | Forwards queued crash reports. No-op unless crash reporting is enabled. |
alerts:evaluate --once | every minute | Evaluates alert rules, opens and resolves alerts, notifies by inbox, email and webhook. No-op while alerting is turned off. See Alerts. |
logs:forward --once | every minute | Forwards new log entries to the configured SIEM webhook. No-op unless log forwarding is enabled. |
firewall:collect --once | every 5 minutes | Reads, parses and stores a firewall snapshot per host with a healthy agent. |
host:scan --once | every 15 minutes | Read-only system and Proxmox scan per host with a healthy agent (the facts shown on the node page). |
vpn:sync --once | every 15 minutes | Re-applies the WireGuard VPN on nodes whose desired state changed. See WireGuard VPN. |
backup:run --once | daily, 02:30 | Builds a panel backup (database dump plus uploads) and pushes it to the configured destinations, enforcing retention. No-op unless panel backups are enabled. |
updates:check --once | daily, 04:40 | Polls the NexoVirt update channel and caches the latest signed release metadata. |
updates:auto-apply --once | hourly, at :07 | Installs the signed bug-fix release picked for automatic updates, if auto-update is on. Never installs a feature release. See Updates. |
license:check | every 5 minutes | Re-validates the license so a renewal, suspension or tier change shows up promptly. Degrades to Community Edition on an invalid license, never blocks the panel. |
dyndns:status | every 5 minutes | Refreshes the status of enabled DynDNS names. No-op without enabled names. See DynDNS. |
pbs:prune --once | hourly | Runs due PBS prune (retention) policies. |
console-proxy:ensure | every minute | Watchdog: checks the console proxy’s listen port and restarts it if it is down. |
Root cron
Section titled “Root cron”One entry runs as root: nexovirt-domain run, every minute. It applies the hostname and TLS settings from
Settings → Domain. It is a root-owned script in /usr/local/sbin, not app code: it asks the app (as the
app user) what to apply, validates every field and reports the result back.
Optional daemon
Section titled “Optional daemon”| Command | Purpose |
|---|---|
plans:enforce [--once] | Suspends plan-assigned guests on expiry or when the traffic limit is exceeded, deletes them after the grace period and resumes traffic-suspended guests on the monthly reset. Off unless enforce.enabled = true in .env, and not scheduled by the installer: run it as a service or from cron if you use plan enforcement. Only touches guests that were created from a plan. |
Workers the panel starts itself
Section titled “Workers the panel starts itself”These are started in the background by a panel action. You only run them by hand to debug, or when the
PHP proc_open function is disabled on your server.
| Command | Started by |
|---|---|
host:onboard <runId> | Set up agent: SSH bootstrap of the node agent. |
agent:op <runId> | Update agent, Remove agent and host delete. |
host:rescan <hostId> | Rescan host facts on the node page (system and Proxmox facts plus the firewall snapshot). |
sdn:provision <projectId> / sdn:deprovision <projectId> | Creating, retrying or deleting an SDN project. |
backup:run --once | Run now under Settings → Backups. |
updates:apply | A manual or automatic panel update (hands off to the root updater). |
Setup and maintenance commands
Section titled “Setup and maintenance commands”| Command | When to use it |
|---|---|
migrate | Applies pending database migrations. The installer and updater run it for you. |
agent:register <label> --host=<id> | Registers a host agent by hand and prints its one-time bearer token. Normally Set up agent does this. |
os-catalog:sync [--force] | Pulls the OS template catalog. Without --force only new templates are added; --force also updates already-synced ones. |
license:check | Re-validates the license right now (for example after activating Enterprise from the shell). |
updates:target auto|manual | Prints the exact release version an automatic or manual update would install. |
updates:verify <tarball> [auto|manual] | Verifies a downloaded release (SHA-256 and signature) before extracting. |
updates:line | Prints the effective release line. |
updates:health | Post-update health check (app boots, database reachable). Exit code 0 or 1. |
docs:error-codes [--out=<path>] | Renders the error-code catalog as a Markdown table. |
Root entrypoints
Section titled “Root entrypoints”Two root-owned scripts in /usr/local/sbin cover the tasks that need root. Root never runs code from the
app-user-owned install directory.
| Command | Purpose |
|---|---|
nexovirt-domain run [--force] | Applies the Settings → Domain state (nginx, certificates). Runs from root cron every minute; --force re-applies. |
nexovirt-domain reset | Lockout escape: restores plain IP access over HTTP if a bad hostname or TLS setting made the panel unreachable. Run by hand on the server. |
nexovirt-update auto|manual | The updater (verify, back up, migrate, roll back on failure). The app user may run only this, through a sudoers rule; the panel calls it for you. |