russel-ctrl as a service: the installer’s systemd unit on Debian, Ubuntu, and similar distributions, or the NixOS module. Both listen on 127.0.0.1:7878 only, require the token, and keep state in /var/lib/russel with mode 0700.
What you’ll need
- A
russel-ctrlbinary for this distribution: a release download, or one built on this machine. A binary built on NixOS won’t run on Debian. sudoonce, to install. Both setups run russel-ctrl and every workload as a dedicated, unprivilegedrusselaccount.- Rootless Podman for containers;
/dev/kvmpluscloud-hypervisor,virtiofsd, andpasstfor microVMs.
Debian, Ubuntu, and other systemd distributions
check lists missing prerequisites with a fix for each and changes nothing. host runs the same checks first (--skip-checks overrides), then:
- Creates the
russelsystem group and account (home/var/lib/russel, no login shell), adds a subuid/subgid range after every existing one, and enables linger souser@<uid>.servicegives it/run/user/<uid>and a user bus from boot. - Adds the invoking
sudouser to therusselgroup, and addsrusseltokvmwhen/dev/kvmexists. - Creates
/etc/russel(root:russel,0750) and/etc/russel/env(root:russel,0640) when missing. Never overwrites, never prints tokens. An old per-user~/.config/russel/envtoken is carried over. - Creates
/var/lib/russel(russel:russel,0700). A directory owned by anyone else is refused unless--take-state-ownership, which hands the whole tree torussel. - Renders
contrib/russel-ctrl.servicewith russel’s uid into/etc/systemd/system/russel-ctrl.service(--force-unitoverwrites a changed unit). - Installs
/usr/local/bin/russel-ctrl, keeping the previous binary; a failed restart puts it back. - Enables or restarts the unit and probes
/vms(bounded). Alive means HTTP 200 with avmsarray, or HTTP 401 withWWW-Authenticate: Bearer realm="russel-ctrl".
russel.service from the NixOS module, a Nix-store unit, and an old per-user install (it prints the steps to move over).
Manual equivalent (Debian/Ubuntu):
contrib/russel-ctrl.service): User=russel, loopback bind, RUSSEL_REQUIRE_AUTH=1, EnvironmentFile=/etc/russel/env, the Nix daemon profile on PATH, XDG_RUNTIME_DIR and the user bus for rootless Podman, Delegate=yes and KillMode=process so apps keep running when the control plane restarts, restart-on-failure.
Why the unit has no PrivateTmp or ProtectSystem
The dedicated, unprivileged russel account is what isolates Russel. The usual systemd sandboxing options break rootless Podman here:
- Podman keeps a small pause process (
catatonit -P) that holds the account’s namespaces, and everypodmancall joins it. It outlives the control plane on purpose, like the apps do. - It keeps the filesystem view of the control plane that first started it. With
PrivateTmp=yes, that view’s/tmpand/var/tmpare deleted when the service restarts, and every later container fails withpasta … Failed to mount empty tmpfs for pivot_root()ormkdir /var/tmp/…: no such file or directory.ProtectSystem=strictwould pin a read-only root the same way.
systemctl edit. The control plane also runs Podman with --cgroup-manager=cgroupfs: from a system unit, systemd won’t let the account’s user manager take over container processes.
NixOS: services.russel
- Listens on
127.0.0.1:7878, requires the token, keeps/var/lib/russelat mode0700, and turns the experimental warm pool off. rootlessPodman(on by default) sets up what rootless Podman needs: it enables Podman, puts/run/wrappersonPATHsonewuidmapis found, turns on linger, and turns offNoNewPrivileges, which blocksnewuidmap. Turn it off only if you won’t run containers.- For microVMs, add
services.russel.microvms.enable = true;and pointservices.russel.microvms.kernelat Russel’s kernel (the release’srussel-kernel-<version>-x86_64.bzImage, or the flake’smicrovm-kernelpackage). For HTTPS, put Caddy, nginx, or Traefik in front (TLS reverse proxy). - The unit waits for
network-online.target, and setsNIX_PATHto the nixpkgs the module was built with, so ctrl can build its helpers.
russel group, the same layout the installer uses. systemd reads it as root, so the group is only for people:
russel group, the laptop steps in Installation work unchanged, scp of /etc/russel/env included.
The module doesn’t install the dashboard. With services.russel.bin = "/usr/local/bin/russel-ctrl", unpack the release’s russel-dashboard-<version>.tar.gz into /usr/local/share/russel/dashboard and ctrl finds it. Anywhere else, set services.russel.extraEnvironment.RUSSEL_DASHBOARD_DIR. Without either, ctrl serves the API only.
Use services.russel, never install.sh host, on NixOS.