{ lib, config, pkgs, ... }: with lib; let cfg = config.roles.remote-build; in { options.roles.remote-build = { enableBuilder = mkOption { type = types.bool; default = false; description = "Enable this machine as a remote build host for other machines"; }; builderUser = mkOption { type = types.str; default = "nix-builder"; description = "User account for remote builders to connect as"; }; builders = mkOption { type = types.listOf (types.submodule { options = { hostName = mkOption { type = types.str; description = "Hostname or IP address of the build machine"; }; systems = mkOption { type = types.listOf types.str; default = [ "x86_64-linux" ]; description = "Supported systems"; }; maxJobs = mkOption { type = types.int; default = 8; description = "Maximum number of parallel build jobs"; }; speedFactor = mkOption { type = types.int; default = 2; description = "Speed factor compared to local building (higher = prefer remote)"; }; supportedFeatures = mkOption { type = types.listOf types.str; default = [ "nixos-test" "benchmark" "big-parallel" "kvm" ]; description = "Supported build features"; }; sshUser = mkOption { type = types.str; default = "nix-builder"; description = "SSH user for connecting to the builder"; }; sshKey = mkOption { type = types.nullOr types.path; default = null; description = "Path to SSH private key for authentication"; }; }; }); default = []; description = "List of remote build machines to use"; }; fallbackToLocalBuild = mkOption { type = types.bool; default = true; description = "Fallback to local building if remote builders are unavailable"; }; }; config = mkMerge [ # Builder host configuration (mkIf cfg.enableBuilder { # Create dedicated builder user users.users.${cfg.builderUser} = { isSystemUser = true; group = cfg.builderUser; description = "Nix remote build user"; home = "/var/lib/${cfg.builderUser}"; createHome = true; shell = pkgs.bashInteractive; openssh.authorizedKeys.keyFiles = []; # Will be populated by client machines }; users.groups.${cfg.builderUser} = {}; # Allow builder user to perform builds nix.settings.trusted-users = [ cfg.builderUser ]; # Allow remote builds services.openssh.enable = true; # Ensure nix-daemon is accessible nix.settings.allowed-users = [ "*" ]; }) # Client configuration (machines using remote builders) (mkIf (cfg.builders != []) { nix.buildMachines = map (builder: { hostName = builder.hostName; systems = builder.systems; maxJobs = builder.maxJobs; speedFactor = builder.speedFactor; supportedFeatures = builder.supportedFeatures; sshUser = builder.sshUser; sshKey = builder.sshKey; }) cfg.builders; nix.distributedBuilds = true; # Use substitutes from remote builders nix.extraOptions = '' builders-use-substitutes = true ''; # Fallback to local build if remote unavailable nix.settings.fallback = cfg.fallbackToLocalBuild; }) ]; }