Skip to navigation

What is Rivet?

Rivet is a configuration management tool for Linux hosts. You describe the state you want in HCL: files, packages, users, services, timers, mounts. Rivet compiles that description into a bundle, one file holding the evaluated configuration and all the content it needs. Then it applies the bundle on the host.

What makes Rivet different:

  • Everything is evaluated before the host is touched. Expressions, modules, templates, data hierarchies and SOPS decryption all run at compile time. The host receives finished desired state, so applying needs no access to your source, cloud storage, or credentials. Apt still needs its package repositories.
  • Every change is journalled before it starts. If a run is interrupted by a crash, reboot, or dropped SSH connection, the next run sees what was in flight, re-inspects the host, and finishes the work. A service restart queued by a run that died still happens.
  • Undeclared properties are left alone. Rivet manages only what you declare. If you don’t set a file’s mode, Rivet keeps whatever mode the file already has.

If you have used Puppet, the model will feel familiar. Facts describe a host, a compiler turns configuration plus facts into a catalog, and a runner converges the host toward it. Rivet differs in shipping the catalog and its file content together as one verified bundle, and in being a single Rust binary.

A small example

package "nginx" {}
file "status" {
path = "/etc/nginx/conf.d/status.conf"
content = "server {\n listen 127.0.0.1:8080;\n location /status { stub_status; }\n}\n"
meta {
depends_on = [package.nginx]
notify = [service.nginx]
}
}
service "nginx" {
ensure = "running"
enabled = true
on_change = "reload"
}

Applying this installs nginx, writes the config file once the package exists, makes sure nginx is running and enabled, and reloads it whenever the config file changes. Applying it again changes nothing. If someone edits the config by hand, the next apply restores it and reloads nginx.

rivet facts --local > facts.json
rivet compile ./configuration --facts facts.json --out host.bundle
rivet plan host.bundle --local
sudo rivet apply host.bundle --local

How it works explains what each of these steps does.

Ways to run it

ModeUse it when
LocalYou are trying Rivet out, or managing a single host.
SSH from a controllerYou want to push changes from a laptop or CI to a few hosts without installing an agent.
Agent with source releasesYou want hosts to pull configuration from S3 or GCS on a schedule.
Agent with the compile serviceYou want compilation off the hosts, or want to classify hosts by verified cloud or certificate identity.

All four use the same runner on the host. Choosing how to run Rivet compares them in more detail.

What it manages

ResourceManages
FileFiles, directories, and symlinks, with ownership, modes, backups, and validation before replacement.
PackageApt packages and bundled .deb archives, with versions, holds, and removal.
UserLocal accounts, passwords, expiry, and home directories.
GroupLocal groups and GIDs.
Group membershipSupplementary group members, either added or managed as an exact list.
ExecCommands guarded by conditions, or run only when notified.
ServiceSystemd units: running, enabled, masked, restart or reload on change.
TimerSystemd timers and the oneshot services they run.
SSH authorized keyIndividual entries in authorized_keys files.
MountActive mounts and their /etc/fstab entries.

Approved plugins can add resource types, service and package backends, and functions.

Status

Rivet is experimental. Managed hosts must run Ubuntu 24.04 on x86_64 or ARM64 with systemd, and applying changes requires root. You can write and compile configuration, and drive hosts over SSH, from macOS or Linux. Bundle and journal formats can change between versions without migration. See limitations for what is not supported yet.

Start with installation and your first configuration.