initrd / boot
There are two main ways to do stage-1 boot in NixOS; via systemd as the init process or NixOS’ custom stage-1 initrd script.
This module focuses on easing configuration of unlocking encrypted disks over SSH during stage-1, and provides support for both systemd and scripted stage-1 as targets.
Systemd initrd boot vs NixOS scripted boot
NixOS scripted boot is a custom stage-1 initrd script generated from options in boot.initrd
and system configuration.
It can be used with systemd-boot
or grub
as a bootloader to boot a NixOS system.
NixOS also supports configuring initrd with systemd running in and managing the initrd process.
This allows configuring systemd services in boot.initrd.systemd.services
, and network configuration in boot.initrd.systemd.network
.
The systemd initrd can be very useful in writing more complex initrd access controls or with more complex hardware and stage-1 requirements.
Usage
Simple (laptop or desktop)
The simplest setup is using both systemd as both the initrd and bootloader, which can be done with:
provision.fs.boot = {
enable = true;
device = "/dev/sda"; # sets `/boot` to a vfat device here
systemd.enable = true;
systemd.initrd.enable = true;
};
In many setups like a laptop or desktop computer, this is often enough.
Grub / BIOS
Some VPSs or older hardware may not support UEFI boot or you may have other reasons for using grub.
provision.fs.boot = {
enable = true;
device = "/dev/sda";
grub.enable = true;
};
Server decrypt drives over SSH
You can enable SSH in the initrd process to allow unlocking encrypted filesystems without being physically at the host.
The private/public key pair used by the host for this stage-1 SSH access is normally stored on the unencrypted boot partition. You should not use the same key pair for the host for the regular openssh daemon, it highly encouraged to generate a new SSH keypair for this purpose only (e.g. with
ssh-keygen -t ed25519 -N "" -C "initrd-root-ssh@host" -f "/etc/initrd/ssh_host_ed25519_key"
)
provision.fs.boot = {
enable = true;
device = "/dev/sda";
systemd.enable = true;
systemd.initrd.enable = true;
initrd.ssh = {
# enable SSH in initrd
enable = true;
# configure the SSH port during initrd
port = 2222; # 9797 by default
# location on disk where initrd SSH only host keys are stored, they are made accessible to the initrd by copying
hostKeys = [ "/etc/initrd/ssh_host_ed25519_key" ]; # default value
authorizedKeyFiles = [ ./mykey.pub ];
# you can add keyfiles from users in `users.users.<name>.ssh.authorizedKeyFiles` with the following option
usersImportKeyFiles = [ "myuser" ];
};
# not all network kernel modules may be present at boot to connect to the network for SSH to be acccessible
# you can add kernel modules to load when initrd is enabled to ensure networks can be configured during initrd
initrd.netModules = [
"8021q" # VLAN
"bridge" # bridge / switch
# example hardware
"r8169"
"igb"
"e1000e"
"i40e"
];
};
You can find which kernel modules you might need to add to provision.fs.boot.initrd.netModules
for your hardware by running
INTERFACE=enp1s0
ethtool -i $INTERFACE | grep driver
Complex Network boots
Some hosts are in environments which require complex network setups to even be accessible to be decrypted.
If you are already using systemd-networkd, you there are some options which can automatically populate
the entries of boot.initrd.systemd.network
with your regular host network configuration.
systemd.network = {
links.wan = { };
netdevs.enp6s0 = { };
netdevs.vlan-18 = { };
networks.bridge = { };
networks.vlan-18 = { };
};
provision.boot.systemd.network = {
# imports all links, netdevs and networks from `systemd.network` to `boot.initrd.systemd.network`
all = true;
# target specific links/netdevs/networks
links = [ "wan" ];
netdevs = [ "enp6s0" "vlan-18" ];
networks = [ "bridge" "vlan-18" ];
};
Wireguard in initrd
TODO