242 lines
9.7 KiB
Nix
242 lines
9.7 KiB
Nix
{ pkgs, lib, modulesPath, inputs, ... }:
|
|
let
|
|
installScript = pkgs.writeShellScriptBin "nixos-install-host" ''
|
|
set -euo pipefail
|
|
|
|
BOLD='\033[1m'
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
NC='\033[0m'
|
|
|
|
header() { echo -e "\n''${BOLD}==> $1''${NC}"; }
|
|
ok() { echo -e "''${GREEN}[ok]''${NC} $1"; }
|
|
warn() { echo -e "''${YELLOW}[warn]''${NC} $1"; }
|
|
die() { echo -e "''${RED}[error]''${NC} $1"; exit 1; }
|
|
|
|
# ------------------------------------------------------------------ #
|
|
# Network #
|
|
# ------------------------------------------------------------------ #
|
|
|
|
header "Network"
|
|
echo "An internet connection is required to download packages during installation."
|
|
echo "If you need Wi-Fi, connect now with: nmtui"
|
|
echo ""
|
|
read -p "Press Enter when the network is ready (or Ctrl-C to abort)..."
|
|
|
|
# ------------------------------------------------------------------ #
|
|
# Host selection #
|
|
# ------------------------------------------------------------------ #
|
|
|
|
header "NixOS Installer"
|
|
echo "Evaluating flake..."
|
|
HOSTS_JSON=$(nix eval "path:/etc/nixos-config#nixosConfigurations" \
|
|
--apply builtins.attrNames --json) \
|
|
|| die "Failed to evaluate the flake at /etc/nixos-config."
|
|
|
|
echo "Available hosts:"
|
|
echo "$HOSTS_JSON" | ${pkgs.jq}/bin/jq -r '.[]' | grep -v installer | sed 's/^/ /'
|
|
echo ""
|
|
|
|
read -p "Host to install: " HOST
|
|
[ -z "$HOST" ] && die "No host specified."
|
|
|
|
# Verify the selected host has disko configured before touching anything.
|
|
# local.notebook.disk is only defined for hosts that include notebook-disko.nix.
|
|
echo "Checking that '$HOST' supports automated installation..."
|
|
nix eval "path:/etc/nixos-config#nixosConfigurations.$HOST.config.local.notebook.disk" \
|
|
--raw > /dev/null 2>&1 \
|
|
|| die "Host '$HOST' does not have a disko configuration. Only 'notebook' is supported."
|
|
ok "Host '$HOST' is supported."
|
|
|
|
# ------------------------------------------------------------------ #
|
|
# Hardware detection #
|
|
# ------------------------------------------------------------------ #
|
|
|
|
header "Detecting hardware"
|
|
echo "Running nixos-generate-config..."
|
|
DETECTED_HW=$(nixos-generate-config --no-filesystems --show-hardware-config 2>/dev/null) \
|
|
|| die "Failed to detect hardware. Is nixos-generate-config available?"
|
|
ok "Hardware detected."
|
|
|
|
# Build a writable copy of the embedded flake and inject the detected
|
|
# hardware config so both disko and nixos-install use the right modules.
|
|
echo "Preparing installation flake..."
|
|
rm -rf /tmp/nixos-flake
|
|
cp -rL /etc/nixos-config /tmp/nixos-flake
|
|
echo "$DETECTED_HW" > /tmp/nixos-flake/modules/_hardware/notebook-hardware.nix
|
|
ok "Hardware config written to flake."
|
|
|
|
FLAKE="path:/tmp/nixos-flake"
|
|
|
|
# ------------------------------------------------------------------ #
|
|
# Disk selection #
|
|
# ------------------------------------------------------------------ #
|
|
|
|
header "Available disks"
|
|
lsblk -d -o NAME,SIZE,MODEL --noheadings | grep -v loop
|
|
echo ""
|
|
|
|
CONFIGURED_DISK=$(nix eval "$FLAKE#nixosConfigurations.$HOST.config.local.notebook.disk" \
|
|
--raw 2>/dev/null || echo "/dev/nvme0n1")
|
|
echo -e "Disk configured for this host: ''${BOLD}$CONFIGURED_DISK''${NC}"
|
|
read -p "Target disk [$CONFIGURED_DISK]: " DISK_INPUT
|
|
DISK="''${DISK_INPUT:-$CONFIGURED_DISK}"
|
|
|
|
[ ! -b "$DISK" ] && die "$DISK is not a valid block device."
|
|
|
|
if [ "$DISK" != "$CONFIGURED_DISK" ]; then
|
|
warn "Disk $DISK differs from configured $CONFIGURED_DISK."
|
|
warn "The disko config will use $DISK regardless, but update local.notebook.disk in"
|
|
warn "modules/_hardware/notebook-disko.nix and commit it after installation."
|
|
fi
|
|
|
|
# ------------------------------------------------------------------ #
|
|
# Age key #
|
|
# ------------------------------------------------------------------ #
|
|
|
|
header "Age key (secrets decryption)"
|
|
KEYS_PATH=""
|
|
|
|
# Search already-mounted media (standard auto-mount paths)
|
|
for candidate in \
|
|
/run/media/nixos/*/keys.txt \
|
|
/run/media/*/keys.txt \
|
|
/run/media/*/*/keys.txt \
|
|
/tmp/keys.txt; do
|
|
if [ -f "$candidate" ]; then
|
|
KEYS_PATH="$candidate"
|
|
ok "Found at $KEYS_PATH"
|
|
break
|
|
fi
|
|
done
|
|
|
|
# When booting via Ventoy the USB data partition (label "Ventoy") is not
|
|
# auto-mounted in the live environment — only the ISO loop device is set up.
|
|
# Detect it by label, mount read-only, copy keys.txt to /tmp, then unmount.
|
|
if [ -z "$KEYS_PATH" ]; then
|
|
VENTOY_DEV=$(${pkgs.util-linux}/bin/blkid -t LABEL="Ventoy" -o device 2>/dev/null | head -1 || true)
|
|
if [ -n "$VENTOY_DEV" ]; then
|
|
warn "keys.txt not found in mounted media. Trying Ventoy partition ($VENTOY_DEV)..."
|
|
VENTOY_MNT=$(mktemp -d)
|
|
if mount -o ro "$VENTOY_DEV" "$VENTOY_MNT" 2>/dev/null; then
|
|
if [ -f "$VENTOY_MNT/keys.txt" ]; then
|
|
cp "$VENTOY_MNT/keys.txt" /tmp/keys.txt
|
|
chmod 600 /tmp/keys.txt
|
|
KEYS_PATH="/tmp/keys.txt"
|
|
ok "Found on Ventoy USB — copied to /tmp/keys.txt"
|
|
else
|
|
warn "Ventoy partition mounted but no keys.txt found at its root."
|
|
echo "Contents of Ventoy root:"
|
|
ls "$VENTOY_MNT" | sed 's/^/ /'
|
|
fi
|
|
umount "$VENTOY_MNT" 2>/dev/null || true
|
|
rm -rf "$VENTOY_MNT"
|
|
else
|
|
warn "Could not mount Ventoy partition $VENTOY_DEV."
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if [ -z "$KEYS_PATH" ]; then
|
|
warn "Age key not found automatically."
|
|
echo "Options:"
|
|
echo " 1. Place keys.txt at the root of the Ventoy USB (alongside the .iso)"
|
|
echo " 2. Mount another USB and it will be found at /run/media/*"
|
|
echo " 3. Enter the path manually below"
|
|
read -p "Path to keys.txt: " KEYS_PATH
|
|
fi
|
|
|
|
[ ! -f "$KEYS_PATH" ] && die "Age key not found at $KEYS_PATH"
|
|
|
|
# ------------------------------------------------------------------ #
|
|
# Confirmation #
|
|
# ------------------------------------------------------------------ #
|
|
|
|
header "Confirmation"
|
|
echo -e " Host : ''${BOLD}$HOST''${NC}"
|
|
echo -e " Disk : ''${BOLD}$DISK''${NC} (ALL DATA WILL BE ERASED)"
|
|
echo -e " Keys : ''${BOLD}$KEYS_PATH''${NC}"
|
|
echo ""
|
|
read -p "Type 'yes' to continue: " CONFIRM
|
|
[ "$CONFIRM" != "yes" ] && { echo "Aborted."; exit 1; }
|
|
|
|
# ------------------------------------------------------------------ #
|
|
# Installation #
|
|
# ------------------------------------------------------------------ #
|
|
|
|
header "Partitioning and formatting"
|
|
echo "(You will be prompted to set the LUKS passphrase.)"
|
|
disko --mode destroy,format,mount --flake "$FLAKE#$HOST"
|
|
|
|
header "Copying age key"
|
|
mkdir -p /mnt/etc/sops/age
|
|
install -m 600 "$KEYS_PATH" /mnt/etc/sops/age/keys.txt
|
|
ok "Age key installed."
|
|
|
|
header "Installing NixOS"
|
|
nixos-install --root /mnt --flake "$FLAKE#$HOST" --no-root-passwd
|
|
|
|
# ------------------------------------------------------------------ #
|
|
# Post-install: save config to the new system #
|
|
# ------------------------------------------------------------------ #
|
|
|
|
header "Saving configuration"
|
|
# Copy the flake (including the detected hardware config) to the user's
|
|
# working directory on the installed system so they can commit it.
|
|
mkdir -p /mnt/home/zoty/repos
|
|
cp -r /tmp/nixos-flake /mnt/home/zoty/repos/nixos
|
|
# UID 1000 is the first normal user, matching the zoty account.
|
|
chown -R 1000:1000 /mnt/home/zoty/repos/nixos
|
|
ok "Configuration saved to ~/repos/nixos on the installed system."
|
|
|
|
echo ""
|
|
ok "Installation complete! Remove the USB drive and reboot."
|
|
echo ""
|
|
echo "After the first boot, commit the detected hardware config:"
|
|
echo " cd ~/repos/nixos"
|
|
echo " git add modules/_hardware/notebook-hardware.nix"
|
|
echo " git commit -m 'add notebook hardware config'"
|
|
echo " git push"
|
|
'';
|
|
in {
|
|
imports = [
|
|
"${modulesPath}/installer/cd-dvd/installation-cd-minimal.nix"
|
|
];
|
|
|
|
# Ventoy's initrd does not support zstd (the NixOS 25.11 default), which
|
|
# causes a -110 timeout and "unable to read id index table" on boot.
|
|
# xz is universally supported by Ventoy across all versions.
|
|
isoImage.squashfsCompression = "xz -Xdict-size 100%";
|
|
|
|
services.getty.autologinUser = lib.mkForce "root";
|
|
|
|
nix.settings = {
|
|
experimental-features = [ "nix-command" "flakes" ];
|
|
tarball-ttl = 0;
|
|
};
|
|
|
|
# NetworkManager instead of wpa_supplicant for nmtui support
|
|
networking.networkmanager.enable = true;
|
|
networking.wireless.enable = lib.mkForce false;
|
|
|
|
environment.systemPackages = [
|
|
installScript
|
|
inputs.disko.packages.${pkgs.stdenv.hostPlatform.system}.default
|
|
pkgs.git
|
|
pkgs.age
|
|
pkgs.sops
|
|
pkgs.jq
|
|
pkgs.neovim
|
|
];
|
|
|
|
# Embed the flake source so the install script can copy it at install time.
|
|
# The script copies it to /tmp/nixos-flake (writable) and injects the
|
|
# detected hardware config before running disko and nixos-install.
|
|
environment.etc."nixos-config".source = ../.;
|
|
|
|
documentation.enable = lib.mkForce false;
|
|
documentation.nixos.enable = lib.mkForce false;
|
|
|
|
system.stateVersion = "25.11";
|
|
}
|