Install minimal NixOS config
Generate the initial config files
nixos-generate-config --root /mntThis will generate the following files:
/etc/nixos/configuration.nix/etc/nixos/hardware-configuration.nix
Create the ZFS config
(
set -euo pipefail
: "${DISK1:?DISK1 is not set}"
: "${DISK2:?DISK2 is not set}"
: "${MNT:=/mnt}"
CFG="${MNT}/etc/nixos/configuration.nix"
MOD="${MNT}/etc/nixos/zfs-root.nix"
[[ -f "$CFG" ]] || { echo >&2 "ERROR: missing $CFG (run nixos-generate-config --root /mnt)"; exit 1; }
P1_DISK1="${DISK1}-part1"
P1_DISK2="${DISK2}-part1"
[[ -e "$P1_DISK1" ]] || { echo >&2 "ERROR: expected ESP path missing: $P1_DISK1"; exit 1; }
[[ -e "$P1_DISK2" ]] || { echo >&2 "ERROR: expected ESP path missing: $P1_DISK2"; exit 1; }
HOSTID="$(head -c4 /dev/urandom | od -A none -t x4 | tr -d ' \n')"
echo "HOSTID: $HOSTID"
# --- Write zfs-root.nix ----------------------------------------------------
cat > "$MOD" <<EOF
{ config, lib, ... }:
let
boot1 = "${DISK1}-part1";
boot2 = "${DISK2}-part1";
in
{
boot.supportedFilesystems = [ "zfs" ];
boot.zfs.devNodes = "/dev/disk/by-id";
networking.hostId = "${HOSTID}";
# nixos-generate-config typically enables systemd-boot on UEFI; turn it off
boot.loader.systemd-boot.enable = lib.mkForce false;
boot.loader.grub = {
enable = lib.mkForce true;
efiSupport = true;
efiInstallAsRemovable = true;
devices = [ "nodev" ];
copyKernels = true;
mirroredBoots = [
{ path = "/boot"; devices = [ boot1 ]; }
{ path = "/boot-fallback"; devices = [ boot2 ]; }
];
};
# Append without self-reference (avoids infinite recursion)
fileSystems."/boot".options = lib.mkAfter [ "nofail" ];
services.zfs.autoScrub.enable = true;
}
EOF
echo "Wrote: $MOD"
# --- Remove systemd-boot enable lines from configuration.nix ---------------
# (so only one bootloader is enabled, and avoid redundant EFI var line)
# --- enable SSH ---
tmp="$(mktemp)"
awk '
# Drop the specific generated comment line (safe)
/^[[:space:]]*#.*systemd-boot EFI boot loader\./ { next }
# Drop enabling systemd-boot
/^[[:space:]]*boot\.loader\.systemd-boot\.enable[[:space:]]*=[[:space:]]*true;[[:space:]]*$/ { next }
# Drop redundant EFI vars line (zfs-root.nix sets it)
/^[[:space:]]*boot\.loader\.efi\.canTouchEfiVariables[[:space:]]*=[[:space:]]*true;[[:space:]]*$/ { next }
# Uncomment OpenSSH enable line if present
/^[[:space:]]*#[[:space:]]*services\.openssh\.enable[[:space:]]*=[[:space:]]*true;[[:space:]]*$/ {
sub(/^[[:space:]]*#[[:space:]]*/, "")
print
next
}
{ print }
' "$CFG" > "$tmp"
cp -f "$tmp" "$CFG"
rm -f "$tmp"
# --- Merge ./zfs-root.nix into existing imports ----------------------------
if grep -q '[[:space:]]\./zfs-root\.nix\b' "$CFG"; then
echo "configuration.nix already imports ./zfs-root.nix; done."
exit 0
fi
# We do NOT create a new imports block. If imports= is missing, fail.
if ! grep -q '^[[:space:]]*imports[[:space:]]*=' "$CFG"; then
echo >&2 "ERROR: no imports= found in $CFG (unexpected)."
exit 1
fi
tmp="$(mktemp)"
awk '
BEGIN { added=0; waiting_bracket=0 }
# Single-line imports: imports = [ ... ];
!added && /^[[:space:]]*imports[[:space:]]*=[[:space:]]*\[.*\][[:space:]]*;[[:space:]]*$/ {
line=$0
sub(/\]/, " ./zfs-root.nix ]", line)
print line
added=1
next
}
# imports = (alone)
/^[[:space:]]*imports[[:space:]]*=[[:space:]]*$/ {
print
waiting_bracket=1
next
}
# imports = [ ... (possibly with trailing comment)
!added && /^[[:space:]]*imports[[:space:]]*=[[:space:]]*\[/ {
print
print " ./zfs-root.nix"
added=1
next
}
# bracket line after a standalone "imports =" (may include trailing comment)
waiting_bracket && /^[[:space:]]*\[/ {
print
if (!added) {
print " ./zfs-root.nix"
added=1
}
waiting_bracket=0
next
}
{ print }
' "$CFG" > "$tmp"
cp -f "$tmp" "$CFG"
rm -f "$tmp"
if ! grep -q '[[:space:]]\./zfs-root\.nix\b' "$CFG"; then
echo >&2 "ERROR: failed to merge ./zfs-root.nix into imports."
echo >&2 "Imports region:"
grep -n 'imports' -A20 "$CFG" >&2 || true
exit 1
fi
echo "Merged ./zfs-root.nix into imports in $CFG"
)Install NixOS (minimal)
nixos-installAt the end it will ask you to set the root password.
Reboot
Unmount filesystems and reboot:
umount -R /mnt
zpool export rpool
reboot