This repository has been archived on 2026-07-19. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
nix-auto-installer/README.md
T
beatzaplentyandClaude Sonnet 5 02ea1929e5 Pre-seed SSH host keys so sops-nix secrets decrypt on first boot
sops-nix (in the nixos flake) derives each host's age decryption key
from its own /etc/ssh/ssh_host_ed25519_key at activation time, which
runs before systemd would otherwise generate that key on first boot
(sshd-keygen is a plain systemd service gated behind multi-user.target;
activation scripts run earlier). Without pre-seeding, secrets --
including the login password -- fail to decrypt on a fresh install's
very first boot.

- scripts/prepare-host-key.sh: run on the admin workstation before an
  install, generates the host's ed25519 keypair and prints the exact
  steps to register its derived age key in nixos/.sops.yaml and
  re-encrypt the affected secrets/*.yaml files.
- common.nix's auto-install.sh: after disko mounts /mnt and before
  nixos-install, installs a pre-seeded key from /root/host-keys/ into
  /mnt/etc/ssh/ if present, otherwise warns and asks for confirmation
  before continuing without one.
- installer.nix now imports common.nix (previously only proxmox-lxc.nix
  did), so the ISO/netboot path used for EFI VM installs gets the same
  auto-install.sh and pre-seed check, not just the LXC path.
- Also fixes a pre-existing stray backtick in the disko invocation that
  broke auto-install.sh's bash syntax entirely, independent of this
  change (found while rendering the script to verify the new logic).

README.md documents the new pre-flight workflow.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-19 13:21:33 +10:00

377 lines
8.5 KiB
Markdown

# Nix Auto Installer
This repository builds a custom NixOS installer environment that can automatically
install any host exposed by a separate NixOS flake.
The installer provides a small NixOS netboot/install environment with SSH access,
Git support, and an interactive installation script. When the `nixos` user logs
in, it runs `/etc/auto-install.sh`, discovers available hosts from the target
flake, allows the operator to choose a system profile, applies the matching
Disko storage configuration, installs NixOS, and reboots.
The installer is designed for a mixed environment where different machines may
have different storage layouts, including Proxmox VMs, Linode instances, and
physical hardware. Disk layout is no longer hardcoded in the installer; it is
defined by each host's NixOS configuration using Disko.
## Repository Layout
* `flake.nix`
* Defines the installer build outputs.
* Builds an `install-iso` image using `nixos-generators`.
* Builds netboot kernel, initrd, and iPXE scripts.
* `installer.nix`
* Defines the installer environment.
* Enables SSH access.
* Configures Git access to the target flake repository.
* Creates the `nixos` and `root` users.
* Provides the generated `/etc/auto-install.sh` installation script.
The installed system configuration lives in a separate NixOS flake. Each target
host is exposed through:
```nix
nixosConfigurations.<hostname>
```
and may optionally include a Disko storage configuration.
## Requirements
The build machine requires:
* Nix installed with flakes enabled.
* Network access to fetch flake inputs.
* Ability to build NixOS images.
The target machine requires:
* Network connectivity during installation.
* A disk defined by its Disko configuration.
* SSH access or local console access.
## Build The Installer ISO
From the repository root:
```sh
nix build
```
The generated installer ISO will be available through the `result` symlink.
The ISO is generated using:
```nix
nixos-generators.nixosGenerate {
format = "install-iso";
}
```
## Build Netboot Components
The flake also exposes netboot components:
```sh
nix build .#netboot-ipxe
nix build .#netboot-initrd
nix build .#netboot-kernel
```
These can be used to PXE boot the installer environment.
## Use The Installer
1. Boot the generated ISO or netboot environment on the target machine.
2. Log in as the `nixos` user.
3. The login shell launches:
```sh
/etc/auto-install.sh
```
4. The installer queries the target flake:
```text
git+https://gitea.lan.ddnsgeek.com/beatzaplenty/nixos.git
```
5. Available installation profiles are discovered from:
```nix
nixosConfigurations
```
6. Select the host profile to install.
7. Confirm the installation.
8. The installer applies the selected host's Disko storage layout.
9. NixOS is installed using the selected flake configuration.
10. The system reboots into the installed OS.
## Storage Management
Disk partitioning is handled by Disko.
The installer no longer contains hardcoded commands such as:
```sh
parted
mkfs.ext4
mkswap
mount
```
Instead, each NixOS host defines its own storage layout.
Example:
```nix
{
disko.devices = {
disk.main = {
type = "disk";
device = "/dev/sda";
content = {
type = "gpt";
partitions = {
root = {
size = "-8G";
content = {
type = "filesystem";
format = "ext4";
mountpoint = "/";
};
};
swap = {
size = "100%";
content = {
type = "swap";
};
};
};
};
};
};
}
```
This allows different hosts to define different layouts:
* Proxmox VMs
* Linode instances
* Physical servers
* ZFS systems
* Future hardware-specific layouts
A host without a Disko configuration will not be automatically partitioned.
## Installer Process
The generated `/etc/auto-install.sh` performs the following steps:
1. Fetch available hosts from the configured NixOS flake.
2. Present available `nixosConfigurations` as a menu.
3. Confirm the selected installation target.
4. Check whether the selected host has a Disko configuration.
5. Run:
```sh
disko --mode destroy,format,mount --flake <flake>#<host>
```
6. Prepare `/mnt` using the Disko-generated mount configuration.
7. Check for a pre-seeded SSH host key at `/root/host-keys/<host>_ssh_host_ed25519_key`
and install it to `/mnt/etc/ssh/` if present (see "Pre-Seeding SSH Host
Keys for sops-nix" below) — prompts for confirmation before continuing
without one.
8. Install NixOS:
```sh
nixos-install \
--flake <flake>#<host> \
--no-root-password
```
9. Remove temporary installation files.
10. Reboot.
## Pre-Seeding SSH Host Keys for sops-nix
The `nixos` flake manages secrets with sops-nix, using an age key derived
from each host's own `/etc/ssh/ssh_host_ed25519_key`. That key is normally
generated by a systemd service (`sshd-keygen`) the first time a host boots
— but sops-nix decrypts secrets (including the login password) earlier
than that, during system *activation*, which runs before systemd starts
pursuing the target that `sshd-keygen` is gated behind. On a genuinely
fresh install, this means secrets fail to decrypt on the very first boot
unless the host key already exists beforehand.
To avoid this, generate the key ahead of time and register it with the
`nixos` flake's sops-nix setup **before** installing:
```sh
./scripts/prepare-host-key.sh <hostname> [path-to-nixos-repo]
```
This generates `host-keys/<hostname>_ssh_host_ed25519_key(.pub)` locally
and prints the exact steps to add its derived age key to `nixos/.sops.yaml`,
re-encrypt the relevant `secrets/*.yaml` files with `sops updatekeys`, and
commit + push the `nixos` repo.
Once that's done and the target machine is booted into the installer,
copy the generated key onto it before running (or continuing)
`/etc/auto-install.sh`:
```sh
scp host-keys/<hostname>_ssh_host_ed25519_key{,.pub} root@<target-ip>:/root/host-keys/
```
`auto-install.sh` checks for this file automatically and installs it to
the target's `/mnt/etc/ssh/` before running `nixos-install`. If it's
missing, the script warns and asks for confirmation before continuing —
useful for hosts that don't consume any sops-nix secrets, but skipping it
for a host that does will lock secrets out of decrypting on first boot.
`host-keys/` is gitignored — never commit private key material.
## Configuration Notes
The installer currently assumes:
* Target flake:
```text
git+https://gitea.lan.ddnsgeek.com/beatzaplenty/nixos.git
```
* Host definitions are under:
```nix
nixosConfigurations
```
* The installer has network access before installation.
* SSH is enabled.
* Root SSH login is permitted.
* The timezone is:
```text
Australia/Brisbane
```
* The target host is responsible for defining its own storage layout.
Change these values in `installer.nix` if your environment differs.
## Security Notes
`installer.nix` currently contains:
* Git credentials
* Password hashes
* SSH public keys
Treat the repository and generated installer images as sensitive.
For production use, consider replacing embedded credentials with:
* Short-lived tokens
* SSH deploy keys
* External secrets management
* Runtime credential injection
## Safety Warnings
This installer is destructive.
The command:
```sh
disko --mode destroy,format,mount
```
will erase any disks defined by the selected host's Disko configuration.
Always verify:
* The selected host profile.
* The Disko device paths.
* The target machine.
Never boot this installer on a machine containing important data unless the
storage configuration has been reviewed.
## Troubleshooting
### No hosts appear in the menu
Check that the installer can reach the flake repository:
```sh
nix eval --json \
"git+https://gitea.lan.ddnsgeek.com/beatzaplenty/nixos.git#nixosConfigurations" \
--apply builtins.attrNames
```
### Selected host has no Disko configuration
The installer checks for:
```nix
config.disko.devices
```
Hosts without Disko storage definitions must either:
* Add a Disko module, or
* Be installed using another storage method.
### Disko evaluation fails
Check the selected host locally:
```sh
nix eval \
".#nixosConfigurations.<host>.config.disko.devices"
```
### Installation fails fetching the flake
Verify:
* Network connectivity.
* Git credentials.
* Flake input availability.
### Installer does not start automatically
Run manually:
```sh
sudo /etc/auto-install.sh
```