# Remote Build Role # # This module configures Nix distributed builds, allowing machines to offload # builds to more powerful remote machines. # # SETUP INSTRUCTIONS # ================== # # 1. BUILDER MACHINE SETUP # On machines that will serve as builders (e.g., zix790prors, john-endesktop): # # a) Enable the builder role in configuration.nix: # roles.remote-build.enableBuilder = true; # # b) After nixos-rebuild, the nix-builder user is created automatically. # You need to add client SSH public keys to the builder. Either: # # Option A - Manual (recommended for initial setup): # sudo mkdir -p /var/lib/nix-builder/.ssh # sudo bash -c 'cat >> /var/lib/nix-builder/.ssh/authorized_keys' << 'EOF' # ssh-ed25519 AAAA... root@client-hostname # EOF # sudo chown -R nix-builder:nix-builder /var/lib/nix-builder/.ssh # sudo chmod 700 /var/lib/nix-builder/.ssh # sudo chmod 600 /var/lib/nix-builder/.ssh/authorized_keys # # Option B - Via NixOS config (if you store keys in the repo): # users.users.nix-builder.openssh.authorizedKeys.keys = [ # "ssh-ed25519 AAAA... root@client-hostname" # ]; # # 2. CLIENT MACHINE SETUP # On machines that will use remote builders (e.g., nix-book): # # a) Configure builders in configuration.nix: # roles.remote-build.builders = [ # { # hostName = "zix790prors"; # maxJobs = 16; # Number of parallel build jobs # speedFactor = 3; # Higher = prefer this builder # } # { # hostName = "john-endesktop"; # maxJobs = 1; # Conservative for busy machines # speedFactor = 1; # } # ]; # # b) Generate SSH key for root (if not exists) and copy to builders: # sudo ssh-keygen -t ed25519 -f /root/.ssh/id_ed25519 -N "" # sudo cat /root/.ssh/id_ed25519.pub # Add this to builder's authorized_keys # # c) Accept the builder's host key (as root): # sudo ssh nix-builder@zix790prors echo "Connected!" # sudo ssh nix-builder@john-endesktop echo "Connected!" # # 3. VERIFY SETUP # Test that distributed builds work: # nix build --rebuild nixpkgs#hello --print-build-logs # # Check builder connectivity: # nix store ping --store ssh-ng://nix-builder@zix790prors # { 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} = {}; # Ensure home directory has correct permissions systemd.tmpfiles.rules = [ "d /var/lib/${cfg.builderUser} 0700 ${cfg.builderUser} ${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; }) ]; }