What is impermanence?
This. Basically because Nix is immutable and
declarative it can rebuild your system from scratch as long as it has the /nix directory. So
you can wipe your root filesystem and Nix will automatically regenerate everything.
It's useful to prevent bloat from accumulating on your computer since it's all wiped away when you restart.
Setup details
I'm using a LUKS encrypted partition with LVM. I have two LVM logical volumes:
An ext4 persistent filesystem for data that should not be deleted, and an
ext4 root filesystem (mounted at /) that gets wiped on restart.
Partition disks
Let's do it, and by it,.. haha well. lets justr say partitioning disks. We want a boot partition and the rest of the space to be a LUKS partition. I've got this installed on a VM using Oracle VBox which only supports legacy EFI so that's what I'll be using. The following is approximately the steps with fdisk:
fdisk /dev/sdX
> o (MBR for legacy EFI)
> n (Create a 500MB boot partition named /dev/sdX1)
> n (Create the root partition named /dev/sdX2, just keep pressing enter)
> w (Write the changes)
mkfs
Now we need to put a FAT filesystem on the boot partition
mkfs.fat -F32 -L NIXOS_BOOT /dev/sdX1
and add LUKS and LVM on the rest of the
drive.
(it's good security to randomize the data on disk before encrypting, the Arch wiki has a useful
tutorial on that
here)
# Setup luks encrypt at /dev/mapper/cryptroot
cryptsetup --label=NIXOS_LUKS luksFormat /dev/sdX2
cryptsetup luksOpen /dev/sdX2 cryptroot
# Setup an LVM volume group named root_vg
pvcreate /dev/mapper/cryptroot
vgcreate root_vg /dev/mapper/cryptroot
Then we'll create two ext4 filesystems, one for the ephemeral root that is wiped on reboot.
lvcreate -L <size> -n root root_vg
mkfs.ext4 -L NIXOS_ROOT /dev/mapper/root_vg-root
And one for the persistent storage that shouldn't be deleted.
lvcreate -l +100%FREE -n persist root_vg
mkfs.ext4 -L NIXOS_PERSIST /dev/mapper/root_vg-persist
Note how we are giving them filesystem labels. This will be useful later when managing our Nix configurations.
Mounting the filesystems
Next we need to mount the filesystems.
mkdir -p /mnt/{boot,persist}
mount /dev/disk/by-label/NIXOS_ROOT /mnt
mount /dev/disk/by-label/NIXOS_BOOT /mnt/boot
mount /dev/disk/by-label/NIXOS_PERSIST /mnt/persist
But remember, Nix still needs the /nix directory to regenerate
properly, so we have to make it persistent. We can use bind mounts for this.
mkdir -p /mnt/{persist,}/{nix,etc/nixos}
mount --bind /mnt/persist/nix /mnt/nix
mount --bind /mnt/persist/etc/nixos /mnt/etc/nixos
We mount /persist/nix to /nix so anything installed into /nix will be
persistent. For convenience we also mounted /etc/nixos. Although not strictly neccessary it
is nice that our configurations are persistent too.
Configurations
Now we can generate our configuration.nix and hardware-configuration.nix.
nixos-generate-config --root /mnt
There are still a few essential changes to be made to the configurations before we can run
nixos-install. Most can be found here but we'll also need
to make a few more edits to support LUKS and to wipe our ephemeral storage on reboot.
First lets add the LUKS partition as a luks device. Make the following changes in
hardware-configuration.nix:
boot.initrd.kernelModules = [ ... "cryptd" ]; # <-- add cryptd as a kernel module
boot.initrd.luks.devices.cryptroot.device = "/dev/disk/by-label/NIXOS_LUKS"; # <-- add luks device
Then we need to mark the /persist directory as neededForBoot or else we won't be
able to boot.
fileSystems."/persist" =
{ device = "/dev/disk/by-label/NIXOS_PERSIST";
fsType = "ext4";
neededForBoot = true; # <-- add neededForBoot
};
And finally we need to wipe the root filesystem on restart by adding the following configuration:
boot.initrd.systemd = {
enable = true;
extraBin."mkfs.ext4" = "${pkgs.e2fsprogs}/bin/mkfs.ext4";
services.wipe-file-systems = {
description = "Wipe the root filesystem";
unitConfig.DefaultDependencies = false;
serviceConfig.Type = "oneshot";
requiredBy = [ "initrd.target" ];
before = [ "local-fs-pre.target" ];
after = [ "initrd-root-device.target" "systemd-hibernate-resume.service" ];
script = ''
mkfs.ext4 -F -L NIXOS_ROOT /dev/disk/by-label/NIXOS_ROOT
'';
};
};
This adds a systemd service that wipes the filesystem by reformating the ext4 filesystem on root.
mkfs.ext4 is not present in the initial ramdisk so it has to be added using
extraBin.
Install
Run nixos install --root /mnt.
and that's my setup! I've been thinking of using disko which is a tool to handle the partitioning automatically. Although, I'm not sure if it's worth the hassle.