NixOS installation media
For now, the installation media only targets my main use case which is deploying workstations:
-
UEFI compatible
x86_64-linux
hosts -
one physical storage device
🔥
|
The build of the installation media image is Flake based. You will need to enable flakes for this to work. |
All development environment constraints should be guaranteed by the provided nix-shell
environment.
Issue nix-shell
or nix-shell --pure
on the command line to start this environment.
This shell will be called the phoenix shell thereafter.
ℹ️
|
Unless stated otherwise, all relative paths (in particular starting with ./ ) assume that the current working directory is the project path.
|
In order to build the installation media image, issue phx-build
in the phoenix shell.
The resulting ISO image will be available in ./result.iso/iso
.
ℹ️
|
Use the standard NixOS installation media creation procedures to obtain a physical installation media. |
Two install procedures are available depending on whether a NixOS configuration flake is available or not for the platform:
-
the new host install procedure is for unconfigured platforms with no existing NixOS configuration to apply
-
the flake install procedure is for platforms registered in a reachable flake configuration
Boot the target on the installation media. Once the boot sequence is complete and the command prompt is available, enter the following commands on the target:
sudo setup-storage <block device>
sudo generate-configuration
sudo nixos-install
sudo reboot
ℹ️
|
It should be |
Follow the same procedure as in New host install but with the following commands on the target:
sudo setup-storage <block device>
# A network connection is needed for the next step, to setup Wi-Fi:
# nmcli device wifi connect <SSID> password <password>
sudo nixos-install --flake <flake URI>#<hostname>
sudo reboot
ℹ️
|
For testing purposes, you can use the following flake configuration:github:gautaz/phoenix#testbox
|
The goal of the setup-storage
command is to ensure the following layout on a block device:
-
boot
as the FAT32 partition used by UEFI -
pv
as the LUKS encrypted device that contains a LVM physical volume which will be part of a volume group namedvg
containing:-
a logical volume named
swap
holding the swap space -
a logical volume named
system
containing a Btrfs filesystem separated in subvolumes:-
root
as the root filesystem -
home
as the users home directories -
nix
as the operating system’s Nix store
-
-
ℹ️
|
The main reasons for this layout are:
|
The only argument required by the command is the block device on which to install the storage layout.
After a few verifications, setup-storage
will ask the following questions:
Enter passphrase for <path of pv device>:
Enter passphrase for /dev/disk/by-label/pv:
ℹ️
|
<path of pv device> is the second partition on the device provided as an argument to setup-storage .
|
The first password asked is the one used by LUKS to encrypt the pv
device.
The second password asked must be the same as the first one as it is used by LUKS to open the pv
device (/dev/disk/by-label/pv
is in fact a symbolic link to <path of pv device>
).
Asking the same password twice offers the additional guarantee that no password misspell occurred.
ℹ️
|
In case of a password mismatch, simply issue the setup-storage command again to start over.
|
Usually having UUIDs in the hardware-configuration.nix
file is not an issue until this file is kept in a git repository for reuse.
The goal of the generate-configuration
command is to avoid identifying the target’s devices in the /mnt/etc/nixos/hardware-configuration.nix
file with UUIDs.
As the setup-storage
command ensures that all devices are accessible through labels, generate-configuration
will simply:
-
generate the target NixOS configuration with
nixos-generate-config --root /mnt
-
replace all UUIDs generated by
nixos-generate-config
with their corresponding labels
Once the target is successfully deployed, the hardware-configuration.nix
file can be kept in configuration in a repository for future use (flake deployment for instance).
ℹ️
|
generate-configuration will also ensure that LUKS opens /dev/disk/by-label/pv on boot to work around this issue.
|
In order to test the installation media image, issue phx-test
to start a test virtual machine from the phoenix shell.
The test VM uses TianoCore UEFI implementation as the installation media is primarily targeted at systems supporting UEFI.
Once the test VM has started, it will boot:
-
either on the installation media if no successful install occurred previously
-
or on a previously successfully installed NixOS system (to discard it simply issue
rm ./disk.qcow2
in a command shell)
If the installation media has started, issue the commands from the Install procedure section on the virtual machine console.
|
Do NOT use these commands on your current host shell, as they may mess up your host operating system if it is NixOS based. |
In order to mount the test VM filesystems on the development host, issue the following command in a phoenix shell:
sudo phx-mount <mountpoint>
Where <mountpoint>
must be a previously created directory.
In order to later unmount the test VM filesystems, issue the following command in a phoenix shell:
sudo phx-umount <mountpoint>
-
✓ Initial extensible ISO image (implemented by the initial revision)
-
✓ Tooling to prepare the local storage (implemented by setup-storage)
-
✓ Tooling to install NixOS (nothing to do, standard NixOS install simply works)
-
✓ Tooling to make
hardware-configuration.nix
more generic -
✓ Tooling to mount test filesystems on the host
-
✓ Tooling to install the NixOS configuration from a flake on a Git server (done with
nixos-install --flake
) -
✓ Add a
shell.nix
file to ensure project’s requirements withnix-shell
-
✓ Ensure hibernate is possible
-
❏ Override
nixos-generate-config
withgenerate-configuration
(and also make it available for installed flake configurations) -
❏ Optionally replace LUKS password by a FIDO2 compatible dongle
Many thanks to Wil Taylor for his marvellous introduction to the Nix world.
His nix-iso project is a wonderful starting point.
I also digged into the following articles: