{ config, lib, pkgs, ... }: let cfg = config.services.remoteBuilder; in { options.services.remoteBuilder = { enable = lib.mkEnableOption "remote Nix build machine"; machines = lib.mkOption { type = lib.types.listOf (lib.types.submodule { options = { hostName = lib.mkOption { type = lib.types.str; description = "Hostname or IP of the remote build machine."; }; port = lib.mkOption { type = lib.types.port; default = 22; description = "SSH port."; }; sshUser = lib.mkOption { type = lib.types.str; default = "builder"; description = "SSH user on the remote build machine."; }; sshKey = lib.mkOption { type = lib.types.str; description = "Path to SSH private key for the builder."; }; systems = lib.mkOption { type = lib.types.listOf lib.types.str; default = [ "aarch64-linux" ]; description = "System types the remote builder can build for."; }; maxJobs = lib.mkOption { type = lib.types.int; default = 4; description = "Max parallel jobs on the remote builder."; }; supportedFeatures = lib.mkOption { type = lib.types.listOf lib.types.str; default = [ "benchmark" "big-parallel" "nixos-test" ]; description = "Features the remote builder supports."; }; }; }); default = []; description = "List of remote Nix build machines."; }; }; config = lib.mkIf cfg.enable { nix.distributedBuilds = true; nix.buildMachines = map (m: { hostName = m.hostName; sshUser = m.sshUser; sshKey = m.sshKey; systems = m.systems; maxJobs = m.maxJobs; supportedFeatures = m.supportedFeatures; }) cfg.machines; # SSH config for port + key (nix.buildMachines has no port option) programs.ssh.extraConfig = lib.concatStringsSep "\n" (map (m: '' Host ${m.hostName} HostName ${m.hostName} Port ${toString m.port} User ${m.sshUser} IdentityFile ${m.sshKey} StrictHostKeyChecking no UserKnownHostsFile /dev/null '') cfg.machines); }; }