Skip to content

Latest commit

 

History

History
94 lines (68 loc) · 3.62 KB

README.md

File metadata and controls

94 lines (68 loc) · 3.62 KB

NixOS-PXE-installer

This collection of Nix expressions creates the files that are necessary for a fully automated installation of a host with a pre-defined NixOS configuration using PXE.

The boot process is as follows.

The install client is configured to perform a PXE boot over one of its network devices. This will trigger a DHCP request to obtain the IP address, netmask, default gateway as well as the name of the boot loader and the IP address of the TFTP server from which it can be downloaded.

The EFI firmware will then proceed to fetch the boot loader image via TFTP. In our case, the boot loader image to be used is created by

$ nix-build -A bootLoader

This will create the symlink "result" to point to the image in the Nix store

$ ls -l result/ total 6160 -r--r--r-- 1 root nixbld 6302208 Jan 1 1970 bootx64.efi -r--r--r-- 1 root nixbld 962 Jan 1 1970 grub.cfg

The file bootx64.efi needs to be transferred to the TFTP server. The file "grub.cfg" is the GRUB configuration that was used to build the loader.

The GRUB loader with EFI support can access the host's NIC through the devices named "efinet" followed by a number. The GRUB command "net_bootp" initiates a BOOTP request, starting with efinet0 and iterating through the interfaces until it gets a response (or the list is exhausted in which case the boot process stops).

Even though the system sends a pure BOOTP request, it does expect a DHCP reply, which is incorrect and requires support on the server side. On the ISC DHCP server, this is accomplished with the option "always-reply-rfc1048 on".

In our case, the boot loader needs the name of a TFTP server from which it can download a Linux kernel. Due to another quirk in GRUB, the required DHCP option (66) can only be obtained if the interface is known in advance. The system uses "efinet0" per default, which can be changed by the NixOS option nfsroo.bootLoader.efinetDHCPInterface.

The name of the TFTP server is resolved via DNS and the boot loader proceeds to download the kernel by the name /nixos/bzImage, i.e. the TFTP server must export the kernel by this exact path name.

The kernel image is generated by

$ nix-build -A kernel

The kernel is called with the following options:

console=ttyS0,115200n8 ip=:::::ethX:dhcp: root=/dev/nfs init=/nix/store/...

where "ethX" is "eth0" by default and can be changed via the NixOS option nfsroot.bootLoader.linuxPnPInterface. This triggers the IP PnP functionality in the kernel, which performs yet another DHCP request on the given interface. Note that we are now in the interface namespace of the kernel and we need to know which name it will assign to the interface.

The kernel asks for the DHCP option that specifies the path of the root file system to mount and proceeds to mount it.

The image of the root file system is generated by

$ nix-build -A tarball

It must be exported read-only to the client by something like

/srv/nixos/nfsroot 130.59.0.0/16(async,ro)

in /etc/exports.

It then executes the program specified in the "init" kernel option, which will convert the read-only NFS root file system to a writeable file system through unionfs-fuse.

Finally, the actual NixOS installer is called, which partitions and formats the local disk and unpacks the tarball that contains the NixOS system with the custom configuration onto the disk.

The hardware-dependent NixOS configuration is created by "nixos-generate-config", which will create the file /etc/nixos/hardware-configuration.nix on the new system. It will also provide a basic network configuration in /etc/nixos/networking.nix according to the NixOS options customInstaller.networking.{useDHCP, staticInterfaceFromDHCP}.