I kept reaching for my laptop when I wanted to test a package change, and every time the fan would spin up, CPU would pin at ninety-five degrees, and I'd watch the battery tick down while nix build churned through dependencies. The homelab machine in the closet — a small-form-factor Intel box with twice the cores, more RAM, and a proper heatsink — sat mostly idle between service deployments.
Nix has a built-in remote build mechanism called the SSH-ng builder. It requires no daemon on the remote side, no CI runner, no custom protocol. The machine just needs to accept SSH connections from a user with Nix daemon trust.
On the server, that means creating a builder user and adding it to trusted-users:
users.users.nix-builder = {
isNormalUser = true;
description = "Remote Nix builder";
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3Nza… nix-builder@maxbook"
];
};
nix.settings.trusted-users = [ "root" "max" "nix-builder" ];
That's the entire server-side configuration. The user has no special capabilities, no sudo, no extra groups — just SSH key access and the Nix daemon's trust list. Everything else is configured and initiated from the laptop.
On the client side, the whole thing is a reusable NixOS module:
nix.distributedBuilds = true;
nix.buildMachines = [
{
hostName = "services-01.home.arpa";
sshUser = "nix-builder";
sshKey = "/path/to/id_ed25519";
protocol = "ssh-ng";
system = "x86_64-linux";
maxJobs = 8;
speedFactor = 2;
supportedFeatures = [ "big-parallel" "kvm" "nixos-test" ];
}
];
The ssh-ng protocol matters. Nix's older SSH builder (ssh://) streamed NAR files over a single connection and couldn't handle builds that needed local store access on the builder. The newer ssh-ng:// protocol runs the full Nix daemon protocol over SSH, so features like content-addressed paths and nix copy work transparently. The builder behaves exactly like a local machine, just over the network.
The supportedFeatures field is what makes this more than a cache warmer. Declaring big-parallel tells Nix the builder has enough cores and memory for the heaviest derivations. kvm and nixos-test mean it can run NixOS VM tests during deployment — something my laptop would struggle with even if I wanted to wait.
The module wraps all of this in a buildFarm abstraction with compile-time assertions, SSH key management, and known-hosts configuration. Flip one option and the laptop becomes the orchestration head of a two-node build cluster. The code is in my infra repo, the same flake that deploys the server itself.