diff options
Diffstat (limited to 'sys/web/sites/pxe.nix')
| -rw-r--r-- | sys/web/sites/pxe.nix | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/sys/web/sites/pxe.nix b/sys/web/sites/pxe.nix new file mode 100644 index 0000000..54f3e56 --- /dev/null +++ b/sys/web/sites/pxe.nix @@ -0,0 +1,180 @@ +{ + config, + flakes, + lib, + pkgs, + ... +}: +with lib; let + cfg = config.local.web.sites.pxe; + + pxeEnabled = machine: machine.config.local.boot.pxe.enable; + machines = listToAttrs (map (name: { + inherit name; + value = flakes.self.nixosConfigurations.${name}; + }) + cfg.machines); + + stage2For = name: machine: + # https://purpleidea.com/blog/2025/01/23/working-around-an-ipxe-issue/ + # "The answer: + # They told me that one of their engineers had struggled with the same issue for a while. The solution: + # Add the imgfree iPXE command before you boot! + # I wish the docs would hint that this is often required, but now I know, and now you know too! + # You can see that line here." + pkgs.writeText "stage2-${name}.ipxe" '' + #!ipxe + echo stage2: booting ${name}... + imgfree + kernel kernel init=${machine.config.system.build.toplevel}/init ${concatStringsSep " " machine.config.boot.kernelParams} || goto fail + initrd initrd || goto fail + boot || + :fail + echo stage2: failed, rebooting in 5 seconds... + sleep 5 + reboot --warm + ''; + + machineLocations = name: machine: let + mac = machine.config.local.boot.pxe.mac; + build = machine.config.system.build; + in { + "= /${mac}/initrd".alias = "${build.initialRamdisk}/initrd"; + "= /${mac}/kernel".alias = "${build.kernel}/${pkgs.stdenv.hostPlatform.linux-kernel.target}"; + "= /${mac}/stage2.ipxe".alias = "${stage2For name machine}"; + }; +in { + options.local.web.sites.pxe = { + enable = mkEnableOption "PXE netboot image server"; + + linkLocal6 = mkOption { + type = types.str; + }; + + network = mkOption { + type = types.str; + }; + + machines = mkOption { + type = types.listOf types.str; + default = []; + }; + }; + + config = mkIf cfg.enable { + assertions = + mapAttrsToList (name: machine: { + message = "PXE boot is not enabled in config '${name}'"; + assertion = pxeEnabled machine; + }) + machines; + + local.web.enable = mkDefault true; + + networking = { + firewall.extraCommands = '' + ip6tables -t filter -A local-input -p udp -i ${cfg.network} --dport 1792 -d ${cfg.linkLocal6} -j ACCEPT + ''; + }; + + services = { + nginx = { + virtualHosts = { + "[${cfg.linkLocal6}]" = { + listenAddresses = ["[${cfg.linkLocal6}]"]; + + addSSL = false; + forceSSL = false; + + locations = mergeAttrsList (mapAttrsToList machineLocations (filterAttrs (_: pxeEnabled) machines)); + }; + }; + }; + }; + + systemd = { + network = { + networks.${cfg.network}.addresses = [ + { + Address = "${cfg.linkLocal6}/128"; + AddPrefixRoute = "no"; + PreferredLifetime = "0"; + } + ]; + }; + + services = { + pxe-store-upload = { + path = [config.nix.package pkgs.sshfs pkgs.squashfsTools]; + + script = let + host = lib.throw "TODO: pxe host"; + machine = machines.${host}; + in '' + set -e + + pxe_ip='${machine.config.local.boot.pxe.linkLocal6}' + pxe_host='${host}' + pxe_system='${machine.config.system.build.toplevel}' + + mountpoint="./pxe-initrd.$pxe_host" + store_img="$mountpoint/nix-store.squashfs" + + mkdir -p "$mountpoint" + + export PATH="/run/wrappers/bin:$PATH" + sshfs \ + "root@[$pxe_ip%${cfg.network}]:/nix/.ro-store-img/" \ + "$mountpoint" \ + -o idmap=user + + nix-store --query --requisites "$pxe_system" | \ + xargs -I{} mksquashfs {} - \ + -stream -comp zstd -one-file-system -no-xattrs \ + >"$store_img.tmp" + + mksquashfs -fix "$store_img.tmp" + + sync "$store_img.tmp" + mv -- "$store_img.tmp" "$store_img" + fusermount3 -u "$mountpoint" + ''; + + serviceConfig = { + #AmbientCapabilities = ["CAP_SYS_ADMIN"]; + #CapabilityBoundingSet = ["CAP_SYS_ADMIN"]; + #BindPaths = ["/dev/fuse"]; + #BindReadOnlyPaths = ["/nix/store"]; + #DeviceAllow = ["/dev/fuse rwm"]; + #DevicePolicy = "closed"; + #MountAPIVFS = true; + ProtectSystem = "strict"; + ProtectControlGroups = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + #PrivateDevices = true; + #PrivateTmp = true; + #PrivateUsers = true; + #TemporaryFileSystem = ["/"]; + #DynamicUser = true; + RuntimeDirectory = "pxe-store-upload"; + WorkingDirectory = "/run/pxe-store-upload"; + }; + }; + }; + + sockets = { + pxe-store-upload = { + after = ["network-online.target"]; + wants = ["network-online.target"]; + wantedBy = ["sockets.target"]; + + socketConfig = { + ListenDatagram = "[${cfg.linkLocal6}]:1792%%${cfg.network}"; + }; + }; + }; + }; + }; +} |
