{ config, pkgs, lib, flake, flakeInputs, ... }: with lib; let cfg = config.nfsroot; in { imports = with flake.nixosModules.systemProfiles; [ tmpfs-root ]; options = { nfsroot = { storeDevice = mkOption { type = types.str; default = "nfsroot:nix-store"; }; registrationUrl = mkOption { type = types.str; default = "http://nfsroot/nix-registration"; }; }; system.build = { storeContents = mkOption {}; }; }; config = { # Don't build the GRUB menu builder script, since we don't need it # here and it causes a cyclic dependency. boot.loader.grub.enable = false; # !!! Hack - attributes expected by other modules. environment.systemPackages = [ pkgs.grub2_efi ] ++ (if pkgs.stdenv.hostPlatform.system == "aarch64-linux" then [] else [ pkgs.grub2 pkgs.syslinux ]); # In stage 1, mount a tmpfs on top of /nix/store (the squashfs # image) to make this a live CD. fileSystems."/nix/.ro-store" = mkImageMediaOverride { fsType = "nfs4"; device = cfg.storeDevice; options = [ "ro" ]; neededForBoot = true; }; fileSystems."/nix/.rw-store" = mkImageMediaOverride { fsType = "tmpfs"; options = [ "mode=0755" ]; neededForBoot = true; }; fileSystems."/nix/store" = mkImageMediaOverride { fsType = "overlay"; device = "overlay"; options = [ "lowerdir=/nix/.ro-store" "upperdir=/nix/.rw-store/store" "workdir=/nix/.rw-store/work" ]; depends = [ "/nix/.ro-store" "/nix/.rw-store/store" "/nix/.rw-store/work" ]; }; nix.settings.use-sqlite-wal = false; boot.initrd.availableKernelModules = [ "nfs" "nfsv4" "overlay" ]; boot.initrd.supportedFilesystems = [ "nfs" "nfsv4" "overlay" ]; services.rpcbind.enable = mkImageMediaOverride false; boot.initrd.network.enable = true; boot.initrd.network.flushBeforeStage2 = false; # otherwise nfs doesn't work boot.initrd.postMountCommands = '' mkdir -p /mnt-root/etc/ cp /etc/resolv.conf /mnt-root/etc/resolv.conf ''; networking.useDHCP = true; networking.resolvconf.enable = false; networking.dhcpcd.persistent = true; system.build.storeContents = [config.system.build.toplevel]; system.build.netbootIpxeScript = pkgs.writeTextDir "netboot.ipxe" '' #!ipxe # Use the cmdline variable to allow the user to specify custom kernel params # when chainloading this script from other iPXE scripts like netboot.xyz kernel ${pkgs.stdenv.hostPlatform.linux-kernel.target} init=${config.system.build.toplevel}/init initrd=initrd ${toString config.boot.kernelParams} ''${cmdline} initrd initrd boot ''; boot.postBootCommands = '' # After booting, register the contents of the Nix store on NFS # in the Nix database in the tmpfs. ${pkgs.curl}/bin/curl ${escapeShellArg cfg.registrationUrl} | ${config.nix.package.out}/bin/nix-store --load-db # nixos-rebuild also requires a "system" profile and an # /etc/NIXOS tag. touch /etc/NIXOS ${config.nix.package}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system ''; }; }