Skip to content

Instantly share code, notes, and snippets.

@Reclyptor
Last active February 26, 2026 03:26
Show Gist options
  • Select an option

  • Save Reclyptor/bb8c843e3ffb066bb734c0b2fc4bd84f to your computer and use it in GitHub Desktop.

Select an option

Save Reclyptor/bb8c843e3ffb066bb734c0b2fc4bd84f to your computer and use it in GitHub Desktop.
NixOS Node Installation Script
#!/usr/bin/env bash
set -euo pipefail
HOSTNAME="${1:-}"
DISK="${2:-}"
REPO_URL="https://github.com/Reclyptor/NixOS.git"
FLAKE_DIR="/tmp/nixos-config"
VALID_HOSTS="archeon fluxeon voideon styxeon bytheon"
# Where the installed system will read the Age identity file from.
# This MUST match your sops-nix config (sops.age.keyFile).
# If yours differs, change it here.
SOPS_KEY_TARGET="/mnt/etc/sops/age/keys.txt"
usage() {
echo "Usage: $0 <hostname> <disk>"
echo ""
echo " hostname One of: $VALID_HOSTS"
echo " disk Target disk (e.g. /dev/nvme0n1 or nvme0n1, /dev/sda or sda)"
echo ""
echo "Example: $0 fluxeon /dev/nvme0n1"
exit 1
}
[ -z "$HOSTNAME" ] || [ -z "$DISK" ] && usage
echo "$VALID_HOSTS" | grep -qw "$HOSTNAME" || { echo "Error: unknown host '$HOSTNAME'"; usage; }
# Allow passing "nvme0n1" instead of "/dev/nvme0n1"
if [[ "$DISK" != /dev/* ]]; then
DISK="/dev/$DISK"
fi
[ -b "$DISK" ] || { echo "Error: '$DISK' is not a block device"; exit 1; }
if [[ "$DISK" == *"nvme"* ]] || [[ "$DISK" == *"loop"* ]]; then
PART="${DISK}p"
else
PART="${DISK}"
fi
echo "=== NixOS + ZFS Install: $HOSTNAME on $DISK ==="
echo ""
read -p "This will DESTROY all data on $DISK. Continue? [y/N] " -r
[[ "${REPLY:-}" =~ ^[Yy]$ ]] || exit 0
# ── 1. Partition ──────────────────────────────────────────────────────
echo "[1/10] Partitioning $DISK..."
sgdisk --zap-all "$DISK"
sgdisk -n 1:0:+1G -t 1:EF00 -c 1:"boot" "$DISK"
sgdisk -n 2:0:0 -t 2:BF00 -c 2:"zfs" "$DISK"
partprobe "$DISK"
sleep 2
# ── 2. Format EFI ────────────────────────────────────────────────────
echo "[2/10] Formatting EFI partition..."
mkfs.fat -F 32 "${PART}1"
# ── 3. Create ZFS pool ───────────────────────────────────────────────
echo "[3/10] Creating ZFS pool (rpool)..."
zpool create -f \
-o ashift=12 \
-O acltype=posixacl \
-O xattr=sa \
-O dnodesize=auto \
-O normalization=formD \
-O mountpoint=none \
-O canmount=off \
-O compression=zstd \
-R /mnt \
rpool "${PART}2"
# ── 4. Create datasets ───────────────────────────────────────────────
echo "[4/10] Creating ZFS datasets..."
zfs create -o canmount=off -o mountpoint=none rpool/nixos
zfs create -o mountpoint=legacy rpool/nixos/root
zfs create -o mountpoint=legacy rpool/nixos/home
zfs create -o mountpoint=legacy rpool/nixos/nix
# ── 5. Mount ─────────────────────────────────────────────────────────
echo "[5/10] Mounting filesystems..."
mount -t zfs rpool/nixos/root /mnt
mkdir -p /mnt/{home,nix,boot}
mount -t zfs rpool/nixos/home /mnt/home
mount -t zfs rpool/nixos/nix /mnt/nix
mount "${PART}1" /mnt/boot
# ── 6. Clone flake and patch boot UUID ────────────────────────────────
echo "[6/10] Cloning NixOS configuration..."
BOOT_UUID="$(blkid -s UUID -o value "${PART}1")"
nix-shell -p git --run "git clone $REPO_URL $FLAKE_DIR"
sed -i "s|XXXX-XXXX|$BOOT_UUID|" "$FLAKE_DIR/hosts/$HOSTNAME/hardware-configuration.nix"
echo " Boot UUID: $BOOT_UUID"
# ── 7. Generate SSH host keys ─────────────────────────────────────────
echo "[7/10] Generating SSH host keys..."
mkdir -p /mnt/etc/ssh
ssh-keygen -t ed25519 -f /mnt/etc/ssh/ssh_host_ed25519_key -N "" -q
ssh-keygen -t rsa -b 4096 -f /mnt/etc/ssh/ssh_host_rsa_key -N "" -q
AGE_KEY="$(nix-shell -p ssh-to-age --run "ssh-to-age < /mnt/etc/ssh/ssh_host_ed25519_key.pub")"
echo " Age public key: $AGE_KEY"
# ── 8. YubiKey decrypt bootstrap (NO updatekeys) ──────────────────────
echo "[8/10] Preparing YubiKey decrypt material for install (no updatekeys)..."
YUBIKEY_IDENTITY="/tmp/yubikey-identity.txt"
echo " Ensuring pcscd is running and CCID driver is available..."
sudo pkill -9 pcscd 2>/dev/null || true
sudo rm -f /run/pcscd/pcscd.comm
sudo rm -rf /var/lib/pcsc/drivers
sudo mkdir -p /var/lib/pcsc/drivers
# Deterministic ccid path (no flakes / no nix-command required)
CCID_OUT="$(nix-instantiate --eval -E '(import <nixpkgs> {}).ccid.outPath' | tr -d '"')"
CCID_BUNDLE="$CCID_OUT/pcsc/drivers/ifd-ccid.bundle"
if [[ ! -e "$CCID_BUNDLE" ]]; then
echo "ERROR: CCID bundle not found at: $CCID_BUNDLE"
exit 1
fi
sudo ln -sf "$CCID_BUNDLE" /var/lib/pcsc/drivers/
# Start pcscd in foreground (keep it alive for the duration of nixos-install)
sudo nix-shell -p pcsclite ccid --run "pcscd --foreground" &
sleep 2
echo " Generating yubikey identity..."
# IMPORTANT: redirect inside the privileged shell so the file is written correctly
sudo nix-shell -p age-plugin-yubikey --run "age-plugin-yubikey --identity --slot 1 > $YUBIKEY_IDENTITY"
echo " Installing identity into target system at: $SOPS_KEY_TARGET"
sudo mkdir -p "$(dirname "$SOPS_KEY_TARGET")"
sudo cp -f "$YUBIKEY_IDENTITY" "$SOPS_KEY_TARGET"
sudo chmod 600 "$SOPS_KEY_TARGET"
# ── 8b. Persist NetworkManager Wi-Fi profiles into target system ──────
echo "[8b/10] Persisting NetworkManager Wi-Fi profiles (if present)..."
sudo mkdir -p /mnt/etc/NetworkManager/system-connections
sudo chmod 700 /mnt/etc/NetworkManager/system-connections
# Use sudo bash so '*' expands as root (works even if you can't list as user)
if sudo bash -lc 'ls -1 /etc/NetworkManager/system-connections/* >/dev/null 2>&1'; then
sudo bash -lc 'cp -a /etc/NetworkManager/system-connections/* /mnt/etc/NetworkManager/system-connections/'
echo " Copied profiles from /etc/NetworkManager/system-connections"
elif sudo bash -lc 'ls -1 /run/NetworkManager/system-connections/* >/dev/null 2>&1'; then
sudo bash -lc 'cp -a /run/NetworkManager/system-connections/* /mnt/etc/NetworkManager/system-connections/'
echo " Copied profiles from /run/NetworkManager/system-connections"
else
echo " No NetworkManager profiles found to copy."
echo " Tip: connect on the live ISO using nmcli first, then rerun."
fi
sudo bash -lc 'chmod 600 /mnt/etc/NetworkManager/system-connections/* 2>/dev/null || true'
# ── 9. Install ────────────────────────────────────────────────────────
echo "[9/10] Installing NixOS (this will take a while)..."
nixos-install --root /mnt --flake "$FLAKE_DIR#$HOSTNAME"
# ── 10. Set user password ─────────────────────────────────────────────
echo "[10/10] Setting password for reclyptor..."
sudo nixos-enter --root /mnt -- passwd reclyptor
echo ""
echo "=== Installation complete ==="
echo ""
echo "To unmount and reboot:"
echo " umount /mnt/boot /mnt/home /mnt/nix"
echo " umount -l /mnt"
echo " zpool export rpool"
echo " reboot"
echo ""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment