Skip to main content
This guide takes you from a fresh Linux host to a registered, online executor. End-state: the host runs nvcl-agent.service, the Hub sees it as online, and you can deploy nodes onto it from the UI. The Agent is the bare-metal / VM executor: it runs as a systemd service and manages each node’s processes as their own systemd units. Choose it when your nodes live on hosts or VMs you already manage and you don’t want a Kubernetes dependency. For the executor concept and the Agent-vs-Operator choice, see Executors. The exception is the container-only chain Igra, whose clients ship as images rather than binaries. The Agent runs it as Docker containers instead of systemd units, and installs and configures the Docker engine itself the first time one is deployed (Ubuntu hosts; see Docker prerequisite).

Prerequisites

  • OS — a linux/x86_64 host with systemd.
  • Privilegesroot or sudo.
  • Network — outbound HTTPS to the Hub (https://hub.novacula.io). No inbound ports are needed.
  • API key — see Connect an executor to issue one. You’ll need the exc_-prefixed key in the next step.
Java is not required — the Agent ships as a self-contained image with its own bundled JRE. Docker isn’t required either, unless you deploy a container-only chain — and then the Agent installs it for you.

Docker prerequisite

Deploying Igra onto an Agent needs a working Docker engine on the host. You don’t prepare one: before such a node’s first launch, the Agent checks whether it can reach the Docker daemon and, if it can’t, adds Docker’s official package repository (pinned, with a checksum-verified signing key), installs docker-ce, enables the daemon, and joins itself to the docker group. It then restarts once so that group membership applies. The step is idempotent — a no-op on a host that already has a working Docker — and Docker stays installed after you delete the node. Auto-install covers Ubuntu. On another distribution it fails with an explicit message rather than guessing at your package manager; install Docker yourself, make sure the Agent’s user can reach the daemon socket, and redeploy. A failed install surfaces as a failed operation on the node, so you see the reason instead of a cryptic launch error. Chains whose clients ship as binaries are unaffected and need no Docker at all.

Docker daemon settings

A container-only node needs more than a running Docker — the Agent also reconciles /etc/docker/daemon.json to the settings the container backend depends on, restarting Docker once if it had to change the file. It sets three things:
  • userns-remap: default — runs node containers in a user namespace, so a node’s files are owned by a remapped, unprivileged uid on the host rather than by real root. This is a hard requirement: if it can’t be turned on, node provisioning fails with an explicit message rather than running the node without the isolation. Turning it on moves Docker’s data root, so images and containers from before it was enabled drop out of docker images / docker ps (they aren’t deleted).
  • userland-proxy: false — publishes container ports in the kernel instead of through a per-port proxy process, so a container sees the caller’s real source address rather than the bridge gateway’s. Anything that judges a request by where it came from — a firewall rule in front of a node’s published port, for one — depends on it.
  • default-address-pools — a wide private range each node’s bridge network carves a subnet from. It defaults to 10.201.0.0/16 in /24 blocks; change it with address_pool_base and address_pool_size under a [docker] section in agent.toml if it clashes with a network your host routes.
The Agent keeps any other keys already in daemon.json but replaces default-address-pools wholesale. On a non-Ubuntu host, or one where userns-remap can’t be activated, apply these yourself and restart Docker before deploying.

Steps

1

Run the installer

The production way to bring a host online is the Hub’s one-line installer: the Hub serves a script that downloads the Agent, writes its config, and starts it as a systemd service — the host then syncs to the Hub and reconciles whatever nodes it’s assigned. From the Connect Executor screen in the UI, copy the command (the Hub renders it for your organization, with your Hub URL already baked in). It looks like this:
The script — served by the Hub and rendered from its latest active Agent release — downloads the self-contained Agent image, verifies its SHA-256 checksum, extracts it to /opt/nvcl/agent, writes /etc/nvcl/agent.toml (mode 0600, with your Hub URL and API key baked in), registers nvcl-agent.service, and starts it. If no active Agent release is published yet, /install.sh returns a 404.
The installer aborts if an agent is already installed (an existing /opt/nvcl/agent binary or /etc/nvcl/agent.toml), so a re-run of curl | sh can’t silently overwrite a working install. To intentionally reinstall, set NVCL_FORCE=1:
Moving an existing executor to a newer version does not use NVCL_FORCEupgrade it from the UI instead (the Hub drives self-update).
2

Confirm online in the UI

From Executors, your new executor row should be online, with capabilities populated for every chain it supports.The executor reports in within a few seconds and the row turns online. If it stays offline:
  • Check journalctl -u nvcl-agent.service -n 100 for auth or network errors.
  • Confirm outbound HTTPS to the Hub URL.
  • Verify the API key was copied without trailing whitespace.

What the installer does

Under the hood, the one-line command:
  1. Downloads the self-contained Agent image tarball from the Hub’s latest active release and verifies its SHA-256 checksum.
  2. Extracts it to /opt/nvcl/agent (launcher bin/agent, jars under lib/, and a bundled JRE under runtime/ — no host Java needed).
  3. Writes /etc/nvcl/agent.toml (mode 0600) with [source] type = "hub", the Hub URL (hub.url), your API key (hub.token), and the executor name.
  4. Registers and starts nvcl-agent.service (start on boot, restart on failure).

What the Agent owns on disk

After install:
The data directory ([agent] data_dir = "/var/lib/nvcl") holds everything the agent manages:
Each node’s processes run as their own systemd units named nvcl-node-<id>-<role>.service. Node data is preserved: removing a node stops and deletes its units and releases its ports, but nodes/<id>/ stays on disk — delete it manually to reclaim space. A container-only chain is the exception. Its roles run as Docker containers rather than systemd units, with the same nodes/<id>/<role>/ directory bind-mounted into the container (at /data/<role>), plus a shared nodes/<id>/secrets/. Inspect those with docker ps instead of systemctl. Removal differs too: the container backend removes the node’s containers, its network, and its whole nodes/<id>/ tree — so unlike a systemd node, nothing is left behind to reclaim, and nothing is left behind to recover either.

Managing the agent on the host

The installer runs the agent for you; you never start the daemon by hand. Manage it with systemctl, and read what it observes with the agent CLI:
Stopping the daemon (sudo systemctl stop nvcl-agent.service) does not stop the nodes — their nvcl-node-<id>-<role>.service units keep running. Uninstall / wipe the host:
Upgrades are driven from the Hub — a dispatched release rides the sync response down and the agent self-updates in place (downloads the new image, verifies its sha256, swaps /opt/nvcl/agent keeping one .prev, and restarts). See Upgrade an executor.

Configuration (agent.toml)

The installer writes /etc/nvcl/agent.toml (mode 0600) for you; edit it afterward to tune behaviour, then sudo systemctl restart nvcl-agent.service (the config is read once at startup). A hub-driven config looks like:
  • [source] type is the one mandatory key; in hub mode [hub] url and token are required (the agent won’t sync without them).
  • Parsing is strict — an unknown key or section is a startup error.
  • In hub mode, telemetry is routed through the Hub automatically; you don’t configure a collector here.
Per-node settings (resources, config-file and CLI-argument overrides, RPC exposure) aren’t in agent.toml — you set them per node in the UI. See Deploy a node and Edit a running node.

Hardening

  • Keep agent.toml mode 0600, owned by root. The API key (hub.token) is the credential.
  • Let the Hub drive upgrades — self-update verifies the sha256 and keeps a .prev for rollback.
  • Restrict outbound to the Hub URL plus the per-chain client download mirrors if you want strict egress.

Next steps