Installing a machine
Needs UEFI, your age key on the machine, and every key in
secrets/secrets.yaml already authored. See Secrets.
nix build .#installer-iso
sudo dd if=result/iso/*.iso of=/dev/sdX bs=4M status=progress oflag=sync
Add your SSH key to vm/authorized_keys before building the ISO, or you cannot
reach the installer over the network. Boot it, then from your workstation:
scp ~/.sops-nix/key.txt nixos@<ip>:/tmp/age.key
ssh nixos@<ip>
On a host this repo already knows
sudo -i
git clone https://git.hu-tao.dev/hutao/nixos-dotfiles && cd nixos-dotfiles
INSTALL_AGE_KEY=/tmp/age.key HOST=hutao-desktop ./install.sh
install.sh is about 120 lines of shell, and its order is the design:
everything that can refuse happens before anything is destroyed.
- Preflight: root, UEFI, the tools, and that the age key is a real age key
and a recipient in
.sops.yaml. A non-recipient key installs cleanly and then cannot decrypt its own passwords. - Secrets: every key the host declares, read from the flake’s own
config.sops.secretsrather than a list in the script, plusluks_passphrase, all present and non-empty, and the two password hashes crypt(3) rather than digests. Checked before the disk gate, because sops-nix fails the build on a missing key and in an install that build isnixos-install, after disko has wiped the disk. - Disk: lists
/dev/disk/by-id/paths and makes you type the disk’s size back. Never/dev/nvme0n1: enumeration order is not stable, and disko wipes whatever the name resolves to. - Pin: writes that choice into
hosts/<host>/disk.nix, asking first if the file names a different disk. disko reads the device out of the flake. - Hardware:
nixos-generate-config --no-filesystems, since disko ownsfileSystems.*. Before the eval, because the flake imports the result. - Dry eval: an eval error here costs a minute; the same error after disko costs the disk.
- disko, then
nixos-install, with the age key seeded to/var/lib/sops-nix/key.txtfirst, for the reason in step 2.
Nothing is prompted for and nothing is written back: every credential comes
out of secrets/secrets.yaml.
| Variable | Meaning |
|---|---|
HOST | which nixosConfigurations entry (default hutao-laptop) |
INSTALL_AGE_KEY | path to the age private key copied in above |
INSTALL_DISK | target disk, required when non-interactive |
INSTALL_NONINTERACTIVE | skip both confirmations; what vm/install-test.sh sets |
The disko CLI is nix run .#disko, this repo’s pinned input, so the tool that
partitions is the same version as the module describing the layout.
The disk layout
modules/disk-layout.nix, LVM-on-LUKS so one passphrase unlocks everything:
p1 ESP 2G, unencrypted -> /boot
p2 LUKS2 "cryptroot" -> LVM -> vg "pool" -> swap / root / home
Sizes and the target device come from hosts/<name>/disk.nix. Only the OS disk
is described: disko describes what to create, and the desktop’s HDD has to
survive a reinstall. There is one LUKS keyslot and no recovery key; see
Known hazards.
Why not disko-install or nixos-anywhere
disko-install would collapse steps 4 and 7 and the key seeding into one
command. But it runs disko with DISKO_SKIP_SWAP=1, and on the 8 GB laptop
nixos-install needs the swap LV that plain disko activates. Without it the
build runs out of memory deep into the install.
nixos-anywhere would replace the script outright, but it installs to a target over SSH from a second machine. This runs on the machine being installed, from its own ISO, which is what recovery assumes: the laptop is what you reach for when something else is broken.
On new hardware
Four files, then the same install.sh.
-
The hardware config, from the live environment, before disko.
--no-filesystemsbecause disko ownsfileSystems.*:nixos-generate-config --no-filesystems --dir /tmp/hw mkdir -p hosts/<name> cp /tmp/hw/hardware-configuration.nix hosts/<name>/ -
Disk sizes and the target device:
cp hosts/hutao-desktop/disk.nix hosts/<name>/ -
hosts/<name>/monitors.lua.hyprland.luarequires it, so an empty file is the minimum. Get real names fromhyprctl monitors alland copyhosts/hutao-desktop/monitors.luafor the shape. -
hosts/<name>/default.nix:_: { imports = [ ../common (import ../../modules/disk-layout.nix (import ./disk.nix)) ./hardware-configuration.nix ]; networking.hostName = "<name>"; system.stateVersion = "26.05"; # never change after install }
Then add it to flake.nix beside hutao-desktop, swapping the
nixos-hardware profiles for the CPU and GPU you have, and add its Syncthing
device ID to modules/syncthing.nix after first boot.