It took me quite a while to get to this setup so I thought I would write a guide to help others and also to discuss feedback and other setups. I have NixOS on a Tuxedo Pulse 14, a Surface Pro 6, a custom gaming PC with intel + nvidia, a ROG Ally, and a Hetzner VPS.
For those who want to jump ahead and just look at the setup, here it is. Everything is open, except for one git-crypt encrypted file where I keep sensitive info. Feel welcome to fork the repo. The setup is LUKS2 encrypted Btrfs root with a swapfile, auto unlock with TPM2, secureboot and a BIOS password.
Existing Config (Advanced)
If you have access to a second computer, have a basic config you can reuse, and have a bit of experience with nix already, I think it’s a much nicer experience to install NixOS from the other computer over the network via nixos-anywhere. This way I could prepare my config how I like it and define the partitioning with disko. It can even generate the hardware configuration and save it while deploying NixOS as described in this quick start document.
Enabling
lanzaboote(secureboot module) should be temporarily removed when deploying withnixos-anywhereand then added back to be applied on the next rebuild.
If you want to use nixos-anywhere but don’t have anything usable running on the target machine - such as a Linux based OS with root or sudo access - you can start up the live installation USB on it and create a root password with passwd. Then you can start nixos-anywhere from the other computer. I only tried doing this with the target PC connected over ethernet, as I didn’t want to bother with setting up WiFi on the CLI after nixos-anywhere reboots the computer into its own environment.
It’s also possible to install your existing config with the nixos-install command on the USB Live Installer. First do the partitioning manually on the CLI or using disko following this guide. Then download your config, generate and add a hardware config if necessary. Finally if you follow the same structure as me, your install command would look something like this:
nixos-install -f <path-to-repo> -A <nixos-config-atrribute-name> --no-channel-copy --no-root-password
Start from Scratch (Simpler)
Use the graphical installer on the Live USB, pick manual partitioning:
- boot
- 1024 MB
- FAT32
- mountpoint /boot
- boot flag
- root
- all the rest space
- BtrFS with encryption
- mountpoint /root
Other filesystems on the root partition will also work but my personal choice is BtrFS right now. Optionally, BtrFS subvolumes can be useful for adding impermanence, but that is outside then scope of this guide.
If you already have a system installed with ext4, here’s an easy to follow guide to convert to btrfs. (Optional)
During manual installation you should select disk encryption which will set it up for you. The new installer uses LUKS2 by default, however if you already have a LUKS1 encypted volume, which doesn’t work with TPM unlock, this simple guide shows you how to upgrade it to LUKS2 and switch to a more secure algorithm after the installation while you’re still on the live USB.
Click through the installer and let it do the installation, which can take a while. After rebooting into the installed system, I would start a nix-shell with nh, git and git-crypt, clone my repo to my home directory, and unlock git-crypt with a key that I exported from another machine. The repo has a top level default.nix which contains NixOS configurations for all of my computers, my home manager setup, and a devenv shell for editing the repo.
# Start a shell with needed packages
nix-shell -p nh git git-crypt
# Clone repo (e.g. from Codeberg)
git clone ssh://git@codeberg.org/<user>/<repo>
cd <repo>
# Unlock git-crypt (you need the keyfile originally used to encrypt the secrets)
git-crypt unlock <key>
Assuming that this is the first time I’m bringing up a new device, I would just create a folder for it within the hosts directory and add a default.nix and a hw.nix. I would copy the contents of the auto generated /etc/nixos/hardware-configuration.nix into this local hw.nix. For the default.nix, something like this:
{ pkgs, nixos-hardware, ... }: {
imports = [
./hw.nix
nixos-hardware.nixosModules.my-device
../../modules/personal.nix
];
# Name
networking.hostName = "<device-name>";
# Swap
swapDevices = [ { device = "/var/swapfile"; size = 10*1024; } ]; # 10 = 8 GB RAM + 2 for padding
# DO NOT CHANGE
system.stateVersion = "25.05";
}
The swapfile will be automatically created based on the config.
Then add a new NixOS configuration in the default module which imports this host directory, like I did for the other devices. If the device already had a working config and needs to be brought up after a fresh clean reinstall, then there is no need to recreate these 2 config files or to re-add it to the repo, just use what’s already there.
When you import a directory and not a specific file it implicitly means importing the
default.nixfrom that directory.
After Installation
At this point we’re still missing the secure boot signing keys, so the config won’t build. Here’s a short guide to set up secureboot. First I would open a nix shell with sbctl and run the key generation command, then the build should already work.
I would remove both .nix files from /etc/nixos/* to avoid accidentally building from that and then build with nh. When building with nh, we must pass in the path to the flake or the default module with attribute name. Generally when we talk about the path to the default module, it’s the directory that contains the default.nix and not the file itself.
nh os switch -f <path> <attribute-name>
# For example I usually navigate to my nixos-configs repo and invoke this for my Tuxedo laptop:
nh os switch -f . tuxedo
Enrolling the secureboot key was a different process for all my machines. On the surface I just ran the enroll command and it just worked after that. On the tower I had to turn ON the Windows 10 WHQL settings in BIOS, switch a newly appeared setting from CSM to UEFI and then put secureboot in a setup state, then reboot and run the enroll command. On the Tuxedo I had to put secureboot into “custom” mode, disable auto enroll of factory keys, and then put it in setup mode.
After enabling secureboot I put a BIOS password on both machines. On some machines it might be relatively easy to reset the BIOS settings and therefore disable secure boot even with a BIOS password set, but at least that will trip the TPM and prevent auto-unlocking of the root partition.
After enrolling the keys and enabling secureboot, make sure to reboot and verify that it works according to the guide.
Finally I enrolled the disk decryption key in the TPM chip. To be secure, make sure to also add PCR15 with value 0 and add tpm2-measure-pcr=yes to crypttabExtraOpts.
systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs="0+2+3+7+8+12+13+14+15:sha256=0000000000000000000000000000000000000000000000000000000000000000" /dev/<root-partition>
# Modify HW config
boot.initrd.luks.devices."luks-<...>" = {
device = "/dev/disk/by-uuid/<...>";
crypttabExtraOpts = [ "tpm2-device=auto" "tpm2-measure-pcr=yes" ];
};
The cryptenroll command and another command to find the name of your encrypted partition are both in my README.
At this point, you should be able to reboot with secureboot enabled and only have to enter your login password, not the encryption password. Depending on your hardware, this setup is fairly secure. As long as your nix configuration doesn’t install malicious software. If an attacker tampers with your unencrypted boot, secureboot will fail, and if they disable secureboot or load a live USB the TPM won’t decrypt your root partition, so they won’t be able to access your data. If they backup and replace your encrypted root partition with an unencrypted malicious setup and then try to unlock the backup with the TPM, it will fail the PCR 15 check thanks to binding it to value 0 and measuring the unlocked system in it after unlocking it.
If they steal your laptop, modify your boot partition, get past your BIOS password, disable secure boot, and return your laptop without you noticing, then you unknowingly turn it on, not notice that secure boot is off, then enter the encryption key to unlock your drive, then they could gain access to your data. Or using cold boot attack…
After you confirmed that everything works, nh clean all can free up some space and make your boot menu cleaner by erasing old boot generations and unused packages.