Build a custom installer ISO
This book will take a slightly unconventional approach to installing NixOS. Instead of using the official NixOS graphical installer ISO, we will build our own custom ISO. While this will take a bit longer the first time you do it, it will greatly enhance your ability to reproduce your environment on any new hardware in the future.
Let’s build a customized, headless NixOS installer ISO that will bake in our personal SSH keys and our WiFi credentials, so that the target machine boots straight onto the home/lab network, and will let us drive the whole install process over SSH, with no monitor or keyboard attached.
To build this custom ISO, you need an existing machine that already
has Nix installed; it does not have to be NixOS. The build script
itself is launched through nix run nixpkgs#babashka, so Nix is the
only requirement on the build host.
Run the script directly over the network, without cloning anything:
nix run --extra-experimental-features "nix-command flakes" \ nixpkgs#babashka -- \ -e '(load-string (slurp "https://raw.githubusercontent.com/EnigmaCurry/sway-home/master/bin/nix_build_iso.bb"))'
Or, if you have a clone of the sway-home repository, run it from there:
./bin/nix_build_iso.bb
Answer the questions to customize the installer:
== Customize your NixOS ISO ==
? Installer hostname (nixos-installer)
Enter the installer hostname (default nixos-installer, this will be
the host name of the live NixOS USB stick, not the final installation
host).
? Build from the default nixpkgs source (github:NixOS/nixpkgs/nixos-26.05)? (Y/n)
Choose the nixpkgs source: the default release channel, another recent
release, nixos-unstable, or a custom flake ref. Press Y for the
default, which is the only version thats been tested to work.
? Select SSH keys from your ssh-agent (or select none to enter keys manually)
[x] 256 SHA256:xxxxxxxx/yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy (ED25519-SK)
[ ] 4096 SHA256:xxxxxxx/vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv root@boulder (RSA)
> [x] 256 SHA256:zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz enigma@flux (ED25519)
[spacebar: toggle one, right/left: select all/none, type to filter, ESC to cancel]
Provide your SSH public keys. If you are running an ssh-agent, you can
select one or more keys directly from it; if you select none it will
offer to let you manually paste keys. The keys are installed for the
root user (password login is disabled), so you log in with ssh root@<ip>.
? Pre-seed WiFi credentials into the ISO? Yes
? WiFi SSID
? WiFi PSK (password)
? NetworkManager connection name
Optionally enter your WiFi SSID and password, so the installer joins your wireless network automatically on boot. The key gets baked into the ISO.
? Enable serial console (kernel + serial getty)? (y/N)
Optionally enable a serial console (kernel console + serial getty).
> Enable webhook notify after network-online? Yes
? Webhook URL (will receive JSON POST) https://my-server-somewhere.example.com/path/to/my/webhook
Optionally enter a webhook URL. Once the network is up, the installer
POSTs a JSON message to it containing the hostname, the local IP
address, the login user, and a ready-to-use ssh command, so you can
find out where it landed on the network. It keeps retrying until it
gets a response, so it will still reach you even if the network only
comes up later. This is commonly used with something like
matrix-hookshot to bridge these notifications to your Matrix chat
client.
All of this is burned into the .iso file you build, including your
SSH public keys and, if you enable WiFi, your WiFi password in
cleartext. Do not publish your .iso file.
After a review screen, the finished ISO is copied to your ~/Downloads
directory, named like <hostname>-<username>-custom-<date>.iso.
Create bootable USB stick
Write the .iso file to a USB drive to boot in your target machine.
You can use a user friendly image writer app like Fedora Media Writer,
or if you know how to identify your USB device file, you can use the
venerable dd:
sudo dd if=~/Downloads/name_of_your.iso of=/dev/name_of_your_usb bs=4M status=progress conv=fsync