UEFI install help, nixos-generate-config not seeing boot partition

Hello, I’m doing my first ever NixOS install on a new SSD on a newly built workstation. I’m running into a problem where nixos-generate-config isn’t seeing my /mnt/boot partition and is not writing that into /mnt/etc/nixos/hardware-configuration.nix. Any suggestions on fixing this are appreciated!

Details:

  • I’m using the graphical installation CD and basing this on the installation instructions there
  • Creating four partitions: boot, root, home, swap at /mnt/boot, /mnt, and /mnt/home respectively.
  • boot is labeled esp for UEFI booting

My parted script that does all this is below. It works with no errors, creates and mounts the partitions as specified.

There is one oddity though - regardless whether I script the boot partition filesystem as fat32 (as recommended in the NixOS install manual for UEFI), or ext4, it’s always created as ext4 after giving the boot partition the label 'esp'.

However, when I run nixos-generate-config --root /mnt, the hardware-configuration.nix file it generates includes configs for root, home, swap partitions, but not the boot partition. That file is below too.

Anyone have any idea what’s causing this? Thanks!

nixos-partition.sh

#!/usr/bin/env bash
#make UEFI (GPT) Partition Table and boot/root/home/swap Partitions for NixOS on 1TB M.2 SSD

#partitions:
#boot: 2GB ESP ext4 or fat32 /mnt/boot; 2GB = 1907.348632812MiB
#root: 100GB ext4 /mnt; 100GB = 95367.431640625MiB
#home: 834GB ext4 /mnt/home; 834GB = 795364.379882813MiB
#swap: 64GB linux-swap; 64GB = 61035.15625MiB

#template for GPT only:
#parted [options] [device] -- mklabel gpt \
#  mkpart ["name" FS-TYPE] START END \
#  set PARTNUMBER OPTION on/off \
#mount DEVICE MOUNTPOINT
#swapon [options] [device]

parted -s /dev/sda -- mklabel gpt \
  mkpart "boot" fat32 1MiB 1908MiB \
  mkpart "root" ext4 1908MiB 97275MiB \
  mkpart "home" ext4 97275MiB 892639MiB \
  mkpart "swap" linux-swap 892639MiB 100% \
  set 1 esp on \
  set 4 swap on
mount /dev/disk/by-label/boot /mnt/boot
mount /dev/disk/by-label/root /mnt
mount /dev/disk/by-label/home /mnt/home
swapon -L swap

hardware-configuration.nix

# Do not modify this file!  It was generated by ‘nixos-generate-config’
# and may be overwritten by future invocations.  Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, modulesPath, ... }:

{
  imports =
    [ (modulesPath + "/hardware/network/broadcom-43xx.nix")
      (modulesPath + "/installer/scan/not-detected.nix")
    ];

  boot.initrd.availableKernelModules = [ "ahci" "xhci_pci" "usb_storage" "usbhid" "sd_mod" "sr_mod" ];
  boot.initrd.kernelModules = [ ];
  boot.kernelModules = [ "kvm-intel" ];
  boot.extraModulePackages = [ ];

  fileSystems."/" =
    { device = "/dev/disk/by-uuid/29c625f6-77d7-4479-ba34-3a5fde2ae014";
      fsType = "ext4";
    };

  fileSystems."/home" =
    { device = "/dev/disk/by-uuid/064c3302-490e-4625-8726-72dd3e884100";
      fsType = "ext4";
    };

  swapDevices =
    [ { device = "/dev/disk/by-uuid/26734874-8990-4395-a5c4-6cf72ff743c7"; }
    ];

  powerManagement.cpuFreqGovernor = lib.mkDefault "powersave";
}

Could it be relevant that you’re mounting /mnt after /mnt/boot? Maybe the latter ends up hiding the former

1 Like

Interesting idea, thanks. I modified the script to your suggestion, and added explicit mkdirs for /mnt/boot and /mnt/home. Now it’s finding the boot and swap partitions, but not root or home :/.

#!/usr/bin/env bash
parted -s /dev/sda -- mklabel gpt \
  mkpart "boot" fat32 1MiB 1908MiB \
  mkpart "root" ext4 1908MiB 97275MiB \
  mkpart "home" ext4 97275MiB 892639MiB \
  mkpart "swap" linux-swap 892639MiB 100% \
  set 1 esp on \
  set 4 swap on
mkdir -p /mnt/boot
mkdir -p /mnt/home
mount /dev/disk/by-label/root /mnt
mount /dev/disk/by-label/boot /mnt/boot
mount /dev/disk/by-label/home /mnt/home
swapon -L swap
# Do not modify this file!  It was generated by ‘nixos-generate-config’
# and may be overwritten by future invocations.  Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, modulesPath, ... }:

{
  imports =
    [ (modulesPath + "/hardware/network/broadcom-43xx.nix")
      (modulesPath + "/installer/scan/not-detected.nix")
    ];

  boot.initrd.availableKernelModules = [ "ahci" "xhci_pci" "usb_storage" "usbhid" "sd_mod" "sr_mod" ];
  boot.initrd.kernelModules = [ ];
  boot.kernelModules = [ "kvm-intel" ];
  boot.extraModulePackages = [ ];

  fileSystems."/boot" =
    { device = "/dev/disk/by-uuid/2dec49a5-c140-4dbe-9d34-b98beb8b17b4";
      fsType = "ext4";
    };

  swapDevices =
    [ { device = "/dev/disk/by-uuid/26734874-8990-4395-a5c4-6cf72ff743c7"; }
    ];

  powerManagement.cpuFreqGovernor = lib.mkDefault "powersave";
}

Something about this isn’t right. You did mkdir before you mounted /mnt. Once you mounted /mnt, then those dirs shouldn’t be visible anymore since they weren’t made on this fs. So the following mount commands would have failed.

1 Like

Yeah I’m getting all kinds of erratic behavior now that I don’t understand. My script is borked and is failing at just creating the partitions now. I’m brain dead now, will pick this up again tomorrow and post any updates. Thanks for taking a look!

You might want to stick a set -e at the start of your script to catch failing commands. But anyway, you should be seeing error messages from the script so it’s kinda weird you weren’t mentioning those

If this is your first installation attempt, consider simplifying your partition scheme to just boot, swap and root, created in that order. Since you are likely to know the sizes you want for boot and swap, you can then consume the rest of the disk for root. After your partitions are created and formatted, mount root on /mnt and then run mkdir -p /mnt/boot to mount the boot partition.

Thanks! In the past I’ve liked to keep /home on its own partition to make it easy to move or backup, and the system files in their own partition to make it easy to reinstall, change distros, etc.

But since posting this thread I discovered Graham Christensen’s “Erase your Darlings” blog post, and that’s exactly what I wanted to do but a much better way of doing it. So I’m working through how to do that instead.

Thanks, good idea. I didn’t mention the errors intitially b/c the script actually worked at first, but subsequent runs began failing. Don’t know why, but doesn’t matter now, moving on to an “Erase your Darlings” setup instead.

1 Like