# basic system installation - The installations presented in this repository are always luks encrypted - For simplicity I'm using device labels rather than uuids - Secure Boot has to be disabled in the firmware, the installer iso isn't signed 1. create the partitions with `cfdisk` or `fdisk` (gpt) - `nvme0n1p1`: 2G, type `EFI System`, otherwise the firmware won't find the bootloader - `nvme0n1p2`: the rest, type `Linux filesystem` the layout should look somewhat like this after the installation ```bash NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS nvme0n1 259:0 0 476.9G 0 disk ├─nvme0n1p1 259:1 0 2G 0 part /boot └─nvme0n1p2 259:2 0 474.9G 0 part └─cryptroot 254:0 0 474.9G 0 crypt ├─lvmroot-swap 254:1 0 20G 0 lvm [SWAP] ├─lvmroot-home 254:2 0 250G 0 lvm /home └─lvmroot-root 254:3 0 204.9G 0 lvm / ``` > Note: `lsblk` may additionally show `/nix/store` as a mountpoint on `lvmroot-root`. This is not a separate partition. NixOS mounts the root device a second time at `/nix/store` with `ro,nosuid,nodev` flags to enforce store immutability at runtime. 2. prepare the installation ```bash # format the boot partition mkfs.fat -F 32 /dev/nvme0n1p1 -n "nixboot" # create an encrypted partition cryptsetup luksFormat -y --label="nixcrypt" /dev/nvme0n1p2 # open the encrypted partition and map it to /dev/mapper/cryptroot cryptsetup luksOpen /dev/nvme0n1p2 cryptroot # create the physical volume pvcreate /dev/mapper/cryptroot # create a volume group inside vgcreate lvmroot /dev/mapper/cryptroot # create the swap volume, half the ram (no hibernation) lvcreate --size 16G lvmroot --name swap # if you desire, create a home volume lvcreate --size 150G lvmroot --name home # create the root volume, leave some space in the vg to grow volumes later # (lvextend -r -L +50G lvmroot/home works while mounted) lvcreate -l 90%FREE lvmroot --name root # format as usual for root partition mkfs.ext4 -L "nixroot" /dev/mapper/lvmroot-root # if you previously made the home partition, do it too mkfs.ext4 -L "nixhome" /dev/mapper/lvmroot-home # format the swap partition mkswap -L "nixswap" /dev/mapper/lvmroot-swap # mount root mount /dev/disk/by-label/nixroot /mnt # mount boot mount --mkdir /dev/disk/by-label/nixboot /mnt/boot # again, if you did the home volume mount --mkdir /dev/disk/by-label/nixhome /mnt/home # turn on swap swapon /dev/disk/by-label/nixswap ``` 3. prepare nixos ```bash # generate templates and update the hardware-configuration.nix nixos-generate-config --root /mnt # no extra kernelModules needed, luks and lvm load dm_crypt and dm_mod themselves # add file systems using labels fileSystems."/" = { device = "/dev/disk/by-label/nixroot"; fsType = "ext4"; }; fileSystems."/boot" = { device = "/dev/disk/by-label/nixboot"; fsType = "vfat"; options = [ "fmask=0077" "dmask=0077" ]; # only root may read /boot }; fileSystems."/home" = { device = "/dev/disk/by-label/nixhome"; fsType = "ext4"; }; swapDevices = [ { device = "/dev/disk/by-label/nixswap"; } ]; # point the bootloader to the luks device boot.initrd.luks.devices."cryptroot" = { device = "/dev/disk/by-label/nixcrypt"; # without this fstrim never reaches the ssd allowDiscards = true; # lower latency on nvme bypassWorkqueues = true; }; ``` 4. install nixos ```bash nixos-install ``` ## how to deploy the initial config - Don't forget to install the bootloader, if you changed it since `nixos-install` - The fresh install has no flakes and no git yet, a temporary shell is enough - If the installer iso is older than the flake's nixpkgs, `--no-reexec` keeps `nixos-rebuild` from re-executing a newer version of itself, which can fail against the older systemd of the fresh install (only needed once) - Set a password for the user before rebooting, `users.nix` doesn't set one ```bash $ export NIX_CONFIG="experimental-features = nix-command flakes" $ nix-shell -p git $ sudo nixos-rebuild --install-bootloader boot --flake .#host_name --no-reexec $ sudo passwd aaron ``` ## how to enable secure boot Secure Boot uses lanzaboote with our own keys, see `modules/nixos/lanzaboote.nix`. Do this after the initial config is deployed and boots. 1. create the keys, before the first rebuild with the lanzaboote module ```bash # the keys end up in /var/lib/sbctl, they never leave the host $ sudo nix run nixpkgs#sbctl -- create-keys ``` 2. import `modules/nixos/lanzaboote.nix` in the host's `configuration.nix`, rebuild and check the signatures ```bash $ sudo nixos-rebuild switch --flake .#host_name # EFI/Linux/*.efi and the bootloader must be signed, kernels in EFI/nixos # are not, lanzaboote checks them by hash $ sudo sbctl verify ``` 3. reboot once with Secure Boot still disabled, to make sure the new entries boot 4. in the firmware (F2), erase all Secure Boot keys, then boot nixos again ```bash # "Setup Mode: ✗ Enabled", the ✗ only means the state is insecure $ sudo sbctl status ``` 5. enroll the keys ```bash # only our own keys, no microsoft keys $ sudo sbctl enroll-keys ``` - sbctl refuses if the TPM eventlog shows option ROMs (e.g. a dedicated gpu). Don't force it, either trust exactly those with `--tpm-eventlog` or microsoft's keys with `--microsoft`. Without either, the firmware may not start the device, in the worst case the machine doesn't boot at all. 6. enable Secure Boot in the firmware and set a firmware password, then check ```bash $ bootctl status | grep "Secure Boot" # enabled (user) $ sudo sbctl status # Secure Boot: ✓ Enabled ``` - If it doesn't boot anymore, disabling Secure Boot in the firmware boots as before - Losing the keys isn't fatal: erase the keys in the firmware and start over at step 1 ## how to unlock the disk with the tpm (laptops) Needs Secure Boot first. The TPM releases the key only with the PIN and while the Secure Boot state (PCR 7) is unchanged. The passphrase stays as fallback. 1. enroll the TPM with a PIN as an additional key slot ```bash # asks for the current passphrase, then the new PIN $ sudo systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=7 --tpm2-with-pin=yes /dev/disk/by-label/nixcrypt ``` 2. import `modules/nixos/tpm-unlock.nix` in the host's `configuration.nix`, rebuild and reboot - If the passphrase is suddenly asked for instead of the PIN, the Secure Boot state changed. After a firmware update that's expected, otherwise investigate before typing the passphrase. To re-enroll: ```bash $ sudo systemd-cryptenroll --wipe-slot=tpm2 --tpm2-device=auto --tpm2-pcrs=7 --tpm2-with-pin=yes /dev/disk/by-label/nixcrypt ``` ## how to upgrade the system ```bash $ cd /path/to/repo $ nix flake update $ sudo nixos-rebuild switch --flake .#host_name $ sudo nix-collect-garbage ``` ## how to use nix-helper The tool nix-helper is installed by this configuration. It simplifies administrating nixos and adds more output to the rebuild command. It also features a diff after a successful build. The command uses the `NH_FLAKE` environment variable to be able to run from whatever directory. Basic commands with a set `NH_FLAKE` variable are: ```bash $ nh os switch $ nh os build $ nh os test $ nh clean all --keep 5 ``` There is also the option to interface with home-manager by using `nh home switch` but this isn't necessary since home-manager is imported as a module in this config.