rivethub

install · agent node

Install an agent node

← Server setup overview

An agent node runs the RivetOS runtime and enrolls against your datahub over SSH. You need a working datahub first.

Requirements

  • Debian 12 or Ubuntu LTS, x86_64 or aarch64, with systemd.
  • Root (sudo) and about 512 MiB free disk (2 GiB comfortable for npm ci).
  • An SSH login on the datahub that can run rivethub-hub — this is your --hub target.
  • The installer runs as root, so BatchMode SSH uses /root/.ssh — copy your key there (or ssh-copy-id as root) before a curl-pipe or sudo run.
  • curl, python3, tar, ssh, flock, and git (bare-metal) — missing ones are installed via apt-get when run as root.
  • docker in PATH only if you choose --docker.

the command

Curl-pipe is supported

node installer — curl-pipe
$ curl -fsSL https://get.rivethub.io/node.sh | sudo bash -s -- --hub owner@192.0.2.10

Or from the distro/ directory of a RivetOS checkout:

node installer — checkout
$ sudo bash install/node.sh --hub owner@192.0.2.10 --name node-a --advertise-host 192.0.2.11

Re-running is safe. Re-run without --hub and the installer resumes HUB_TARGET / NODE_NAME from $RIVETHUB_ROOT/node.env.

the prompts

What the installer asks

On a TTY, unset fields are prompted, then a SUMMARY, then an explicit yes. --yes skips the confirm; on non-TTY it also accepts documented defaults (name = hostname, advertise-host = hostname -f). --hub has no default — missing answers are listed together with their env names (RIVETHUB_HUB).

  • Datahub SSH target — the user@host for --hub. Required when stdin is not a TTY and no node.env has one recorded.
  • Mesh node name — the certificate CN ([a-z0-9-], max 63). Default: the hostname, sanitized.
  • Advertise host — the address other nodes use to reach this node. Default: hostname -f.

Enrollment happens over SSH: the installer runs rivethub-hub enroll <node-name> <advertise-host> on the datahub, and stdout is only a base64 tarball (leaf cert + key, ca-chain.pem, current mesh.json, node config snippet), unpacked into the local shared dir. On an existing RivetOS install, rivetos mesh enroll drives the same contract from the CLI.

layout

What gets installed where

/opt/rivetos
RivetOS checkout at the pins/stable.json rivetos_tag (bare-metal; Node 22+ from NodeSource)
/var/lib/rivethub/shared
local mesh.json + rivet-ca (RIVETOS_SHARED_DIR)
/rivet-shared
symlink to the shared dir, so hardcoded RivetOS TLS paths work
/home/rivet/.rivetos
config.yaml + .env (mode 0600) for the rivet user (uid 2000 if free)
/var/lib/rivethub/node.env
recorded identity (node name, hub target) — no secrets
/etc/systemd/system/rivetos-agent.service
the agent unit (enabled + started)

Bare-metal (systemd) is the default. --docker runs the pinned GHCR image under systemd with host networking on mesh port 3000.

Installer versions. The installer uses the runtime tag and container image in pins/stable.json. Check Releases for the distinction between installer pins, runtime releases, and desktop downloads.

verify

Verify

on the node
$ systemctl status rivetos-agent.service
$ journalctl -u rivetos-agent.service -n 50
$ sudo -u rivet -H rivetos status
$ sudo -u rivet -H rivetos doctor

The systemd unit is rivetos-agent.service (not rivetos.service). The mesh certificate lives at /var/lib/rivethub/shared/rivet-ca/issued/<node-name>.crt.

Day-2 mesh sync / renew run as the rivet user (the installer generated /home/rivet/.ssh/id_ed25519 and installed the pubkey on --hub via the root hop):

as rivet
$ sudo -u rivet -H rivetos mesh sync
$ sudo -u rivet -H rivetos mesh renew

next

Add the next node

Run the same command on another host, with a fresh name and address:

second node
$ curl -fsSL https://get.rivethub.io/node.sh | sudo bash -s -- --hub owner@192.0.2.10 --name node-b --advertise-host 192.0.2.11

Renew certificates

Renewal is driven from the datahub: rivethub-hub renew <node-name> re-issues the node’s leaf certificate and emits the same tarball as enrollment. To change a node’s address, re-enroll it instead of renewing.