Deploying to remote machines

Once a config lives in a flake, you do not have to sit at the target machine to apply it. nixos-rebuild can build a configuration and activate it on a remote host over SSH, and a few higher level tools add safety and scale on top of that.

The built-in way with nixos-rebuild

nixos-rebuild understands two location flags. --target-host is the machine where the configuration is activated, and --build-host is the machine that compiles it. Point both at the server to build and switch entirely on the remote.

nixos-rebuild switch \
  --flake .#server \
  --target-host root@server.example.com \
  --build-host root@server.example.com

Omit --build-host to build on your laptop and copy the finished closure to the server, which is handy when the server is small and your laptop is fast.

nixos-rebuild switch --flake .#server --target-host root@server.example.com

If you connect as a normal user rather than root, add --use-remote-sudo so the activation step runs with sudo on the far side.

nixos-rebuild switch --flake .#server \
  --target-host you@server.example.com --use-remote-sudo

Prerequisites

Three things need to be true before any of this works. You need SSH access to the host, the host already needs to be running NixOS, and the flake needs to expose the host as nixosConfigurations.<host>. The first deploy onto a machine that is not yet running NixOS is a different job, covered by nixos-anywhere below.

Copying closures directly

Sometimes you just want to move a built result to another machine without activating anything. nix copy sends a store path over SSH.

# build locally, then copy the result to the server's store
nix build .#nixosConfigurations.server.config.system.build.toplevel
nix copy --to ssh://root@server.example.com ./result

Higher level tools

The built-in flags are enough for one host. For more than that, reach for a tool built around deployments.

  • deploy-rs builds each node, copies the closure, and activates with an automatic rollback if the new system fails to come back online. It is a good fit when you cannot afford to lose access to a remote machine.
  • colmena describes a fleet of hosts in one file and deploys them in parallel, which suits a set of servers you manage together.
  • nixos-anywhere installs NixOS onto a machine that is not running it yet, including partitioning, over SSH. Use it for first-time provisioning.

A minimal deploy-rs node looks like this in the flake.

{
  deploy.nodes.server = {
    hostname = "server.example.com";
    profiles.system = {
      user = "root";
      path = deploy-rs.lib.x86_64-linux.activate.nixos
        self.nixosConfigurations.server;
    };
  };
}
nix run github:serokell/deploy-rs -- .#server

A multi-host flake recap

One flake can hold many hosts that share a common module. Deploy whichever one you mean by naming it after the #.

outputs = { self, nixpkgs, ... }: {
  nixosConfigurations = {
    laptop = nixpkgs.lib.nixosSystem {
      system = "x86_64-linux";
      modules = [ ./common.nix ./laptop.nix ];
    };
    server = nixpkgs.lib.nixosSystem {
      system = "x86_64-linux";
      modules = [ ./common.nix ./server.nix ];
    };
  };
};
# deploy only the server, from your laptop
nixos-rebuild switch --flake .#server \
  --target-host root@server.example.com

Advanced

For repeated remote builds, register build machines so heavy compiles run on a beefier host with nix.buildMachines. Pairing that with a shared binary cache means most paths are downloaded rather than built, which makes remote deploys fast even over a slow link.

{
  nix.buildMachines = [{
    hostName = "builder.example.com";
    systems = [ "x86_64-linux" ];
    maxJobs = 8;
    sshUser = "nix";
  }];
  nix.distributedBuilds = true;
}

Next

For the flake outputs you deploy see Flakes, for full host configs see Examples, for keeping credentials off the wire see Secrets management, and for the commands behind these workflows see Commands and scripts.