NixOS boot drive without dd (UEFI only)

(Disclaimer: I will describe something that is unsupported. I have tried this, but it doesn’t mean it will work for you or keep working. Know what you are doing before you actually do.)

Only the steps:

Make sure you’re on UEFI. Get a drive with a FAT32 partition (GPT/MBR partition . And either:

Method one

Unpack everything to the root of your drive, and do either:

  • Boot from the drive until the boot process fails, enter interactive shell by pressing i, mount your partition at /mnt-root/iso or wherever it says the device couldn’t be mounted at, and exit the shell to continue the boot, or
  • In /EFI/boot/grub.cfg replace every instance of root=LABEL=... with root=/dev/disk/..., where /dev/disk/... identifies your FAT32 partition.

Method 2 using findiso

  • Unpack only the /boot and /EFI directories from the .iso into the root of your drive
  • Copy the .iso file itself into your drive
  • Prepend the following line to /EFI/boot/grub.cfg, replacing the file name with your actual .iso file name
set iso_path=/latest-nixos-plasma5-x86_64-linux.iso

For some reason copytoram doesn’t seem to work for this method.

Again, these are based on my own understanding and experimentation and are not in any way official or supported.

The following is based on my experience with NixOS 20.03.

The problem

As we all know, using dd is the officially supported way to create a NixOS drive from an image, and it is in fact the case for many (most?) other distros as well. But one drawback of this method is also obvious: you lose your partitions in your drive, and if you want to use it as a normal drive you have to repartition and reformat it.

One thing I’ve heard is that for UEFI systems, most of these .iso files (even Windows ones if the largest file fits in 4GB) can be directly unpacked to a FAT32 drive. Then UEFI recognizes /EFI/boot/bootx64.efi and runs it, which is a bootloader that loads the rest of the live system.

However this doesn’t seem to work with NixOS images. The part where things get stuck is that the images waits for /dev/root to appear, but it doesn’t, so it fails to boot.

What to do

If at this point you want to continue, you can go in a shell by pressing i. You’ll see that it’s trying to mount /dev/root which symlinks to a non-existing partition with label like nixos-plasma… which is of course would be the ISO had you used dd, but you only copied the files to your partition. The boot however will work with your partition. Now if you just mount your drive to /mnt-root/iso and exit the shell, boot will happily continue and the rest of the boot drive works just as well as a dd-made one, as far as I can see.

On the other hand you can also fix the cause. /dev/root is specified according to the root=... kernel comman,d line parameter. So just find some persistent way to refer to your partition like /dev/disk/by-partuuid/<foo> and you can simply go into /EFI/boot/grub.cfg and replace every occurence of root=... with root=/dev/disk/by-partuuid/<foo>, and you have a fully working NixOS boot drive.

The truth, and more…?

All this happens in what’s called ‘stage 1’ of the NixOS boot process. contains literally everything about the early boot process (userland part, of course).

Here we also find other mysterious stuff. What’s findiso? Can we also use this to create bootable images by copying out only bootloader+kernel+initrd, and adding a findiso parameter? Why is it undocumented? I have not yet investigated.

Also, I haven’t used Unetbootin, so I don’t know anything about that.

Clicky stuff