Simplify installer script to non-interactive flow

This commit is contained in:
randogoth 2026-02-01 20:43:53 +02:00
parent defa82c46c
commit cd49f479dd
2 changed files with 27 additions and 203 deletions

View file

@ -1,17 +1,16 @@
NixOS installer (flake + Lix)
=============================
1) Build is prewired with Lix; the installer ISO includes the repo.
2) Run the guided Btrfs installer:
1) Build is prewired with Lix; the installer ISO includes the repo at /etc/nixos.
2) Run the non-interactive Btrfs installer (set envs as needed):
sudo ./scripts/install-btrfs.sh
sudo DISK=/dev/vda HOSTNAME=nixos /etc/nixos/scripts/install-btrfs.sh
- Interactive by default (choose disk, LUKS, swap).
- Non-interactive example:
sudo NON_INTERACTIVE=1 USE_LUKS=1 LUKS_PASSPHRASE='secret' SWAP_GB=4 DISK=/dev/sda HOSTNAME=myhost ./scripts/install-btrfs.sh
Defaults: DISK=/dev/vda, HOSTNAME=nixos
The script wipes the disk, creates Btrfs subvolumes (root, home, nix), copies the flake, generates hardware config, and installs with the chosen host name.
3) After install finishes, reboot into the new system.
Notes
- Filesystem is always Btrfs with subvolumes: root, home, nix (and swapfile if enabled).
- Filesystem is Btrfs with subvolumes: root, home, nix.
- The flake lives under /etc/nixos on the target; edit hosts/<hostname>.nix to customize.

217
scripts/install-btrfs.sh Executable file → Normal file
View file

@ -1,220 +1,48 @@
#!/usr/bin/env bash
set -euo pipefail
# Automated Btrfs install using the flake in this repo.
# Defaults remain environment-driven for headless use.
# Interactive prompts are shown unless --non-interactive is set.
# Non-interactive Btrfs installer using the flake in this repo.
# Defaults: DISK=/dev/vda HOSTNAME=nixos
NON_INTERACTIVE=0
if [[ "${1:-}" == "--non-interactive" ]]; then
NON_INTERACTIVE=1
shift
fi
DISK=${DISK:-/dev/vda} # full-disk target
ROOT_PART=${ROOT_PART:-} # optional existing root partition
BOOT_PART=${BOOT_PART:-} # optional existing boot (FAT) partition
HOSTNAME=${HOSTNAME:-nanuqsaurus}
USE_LUKS=${USE_LUKS:-0} # 1 to encrypt root
SWAP_GB=${SWAP_GB:-0} # swap size in GB, 0 disables
DISK=${DISK:-/dev/vda}
HOSTNAME=${HOSTNAME:-nixos}
SCRIPT_DIR=$(cd -- "$(dirname "${BASH_SOURCE[0]}")" && pwd)
REPO_ROOT=$(cd -- "${SCRIPT_DIR}/.." && pwd)
has_cmd() { command -v "$1" >/dev/null 2>&1; }
echo "[1/7] Partitioning ${DISK}"
printf "label: gpt\n,550M,U\n,,L\n" | sfdisk "${DISK}"
prompt_select() {
local title="$1" prompt="$2" choices=("${@:3}")
if (( NON_INTERACTIVE )); then
echo "${choices[0]}"
return
fi
if has_cmd dialog; then
dialog --no-cancel --menu "$prompt" 15 60 6 "${choices[@]}" 2> /tmp/choice
cat /tmp/choice
elif has_cmd whiptail; then
whiptail --notags --menu "$prompt" 15 60 6 "${choices[@]}" 2> /tmp/choice || true
cat /tmp/choice
else
echo "$prompt"
select c in "${choices[@]}"; do echo "$c"; break; done
fi
}
echo "[2/7] Formatting"
mkfs.fat -F 32 "${DISK}1"
mkfs.btrfs -f "${DISK}2"
prompt_yes_no() {
local prompt="$1" default="${2:-n}"
if (( NON_INTERACTIVE )); then
[[ "$default" =~ ^[Yy]$ ]] && echo "yes" || echo "no"
return
fi
if has_cmd dialog; then
if dialog --yesno "$prompt" 8 60; then echo "yes"; else echo "no"; fi
elif has_cmd whiptail; then
if whiptail --yesno "$prompt" 8 60; then echo "yes"; else echo "no"; fi
else
read -rp "$prompt [y/N]: " ans
[[ "${ans:-$default}" =~ ^[Yy]$ ]] && echo "yes" || echo "no"
fi
}
prompt_input() {
local prompt="$1" default="$2"
if (( NON_INTERACTIVE )); then
echo "$default"
return
fi
if has_cmd dialog; then
dialog --inputbox "$prompt" 8 60 "$default" 2>/tmp/input && cat /tmp/input || echo "$default"
elif has_cmd whiptail; then
whiptail --inputbox "$prompt" 8 60 "$default" 2>/tmp/input && cat /tmp/input || echo "$default"
else
read -rp "$prompt [$default]: " ans
echo "${ans:-$default}"
fi
}
ls_disks() {
lsblk -dpno NAME,SIZE,TYPE | awk '$3=="disk"{print $1" "$2}'
}
if (( ! NON_INTERACTIVE )); then
mapfile -t disks < <(ls_disks)
if ((${#disks[@]})); then
disk_choices=()
for d in "${disks[@]}"; do
disk_choices+=("$d" "")
done
DISK=$(prompt_select "disk" "Select target disk (will be wiped)" "${disk_choices[@]}")
DISK=${DISK%% *} # strip size suffix from selection
fi
target_mode=$(prompt_select "mode" "Partitioning mode" \
"full-disk" "Use entire disk (wipes!)" \
"existing" "Use existing partitions")
if [[ "$target_mode" == "existing" ]]; then
ROOT_PART=$(prompt_input "Root partition (will be formatted btrfs)" "${ROOT_PART:-/dev/vda2}")
BOOT_PART=$(prompt_input "Boot EFI partition (FAT32)" "${BOOT_PART:-/dev/vda1}")
fi
USE_LUKS=$(prompt_yes_no "Encrypt root with LUKS?" "n")
[[ "$USE_LUKS" == "yes" ]] && USE_LUKS=1 || USE_LUKS=0
SWAP_GB=$(prompt_input "Swap size in GB (0 = none)" "${SWAP_GB}")
fi
echo "[0/8] Summary:"
echo " Disk: ${DISK}"
if [[ -n "$ROOT_PART" ]]; then
echo " Root partition: $ROOT_PART"
echo " Boot partition: $BOOT_PART"
else
echo " Mode: full disk wipe"
fi
echo " LUKS: $([ "$USE_LUKS" -eq 1 ] && echo enabled || echo disabled)"
echo " Swap: ${SWAP_GB}G"
echo " Hostname: ${HOSTNAME}"
if (( NON_INTERACTIVE )); then
echo "Proceeding in non-interactive mode."
else
if [[ "$(prompt_yes_no "Proceed with these settings? This will destroy data." "n")" != "yes" ]]; then
echo "Aborted."
exit 1
fi
fi
part_boot=""
part_root=""
mapper_root=""
echo "[1/8] Partitioning/selection"
if [[ -z "$ROOT_PART" ]]; then
if [[ ! -b "$DISK" ]]; then
echo "Error: target disk ${DISK} not found. Available disks:"
ls_disks
exit 1
fi
printf "label: gpt\n,550M,U,boot\n,,L,cryptroot\n" | sfdisk "${DISK}"
part_boot="${DISK}1"
part_root="${DISK}2"
else
part_boot="${BOOT_PART}"
part_root="${ROOT_PART}"
fi
echo "[2/8] Formatting boot"
mkfs.fat -F 32 "${part_boot}"
echo "[3/8] Preparing root"
if [[ "$USE_LUKS" -eq 1 ]]; then
pass=${LUKS_PASSPHRASE:-}
if [[ -z "$pass" && $NON_INTERACTIVE -eq 0 ]]; then
pass=$(prompt_input "LUKS passphrase" "")
fi
if [[ -z "$pass" ]]; then
echo "LUKS passphrase required for encrypted install"
exit 1
fi
printf "%s" "$pass" | cryptsetup luksFormat "${part_root}" -
printf "%s" "$pass" | cryptsetup open "${part_root}" cryptroot -
mapper_root="/dev/mapper/cryptroot"
else
mapper_root="${part_root}"
fi
mkfs.btrfs -f "${mapper_root}"
echo "[4/8] Creating Btrfs subvolumes"
echo "[3/7] Creating Btrfs subvolumes"
mkdir -p /mnt
mount "${mapper_root}" /mnt
mount "${DISK}2" /mnt
btrfs subvolume create /mnt/root
btrfs subvolume create /mnt/home
btrfs subvolume create /mnt/nix
umount /mnt
echo "[5/8] Mounting subvolumes"
mount -o compress=zstd,subvol=root "${mapper_root}" /mnt
echo "[4/7] Mounting subvolumes"
mount -o compress=zstd,subvol=root "${DISK}2" /mnt
mkdir -p /mnt/{home,nix,boot}
mount -o compress=zstd,subvol=home "${mapper_root}" /mnt/home
mount -o compress=zstd,subvol=nix "${mapper_root}" /mnt/nix
mount "${part_boot}" /mnt/boot
mount -o compress=zstd,subvol=home "${DISK}2" /mnt/home
mount -o compress=zstd,subvol=nix "${DISK}2" /mnt/nix
mount "${DISK}1" /mnt/boot
if [[ "${SWAP_GB}" -gt 0 ]]; then
echo "[5b/8] Creating swapfile (${SWAP_GB}G)"
mkdir -p /mnt/swap
chattr +C /mnt/swap || true
fallocate -l "${SWAP_GB}G" /mnt/swap/swapfile
chmod 600 /mnt/swap/swapfile
mkswap /mnt/swap/swapfile
swapon /mnt/swap/swapfile
fi
echo "[6/8] Copying flake to /etc/nixos"
echo "[5/7] Copying flake to /etc/nixos"
mkdir -p /mnt/etc/nixos
if command -v rsync >/dev/null 2>&1; then
rsync -a --exclude '.git' --exclude 'result' --exclude 'node_modules' "${REPO_ROOT}/" /mnt/etc/nixos/
else
(cd "${REPO_ROOT}" && tar -cf - --exclude=.git --exclude=result --exclude=node_modules .) | (cd /mnt/etc/nixos && tar -xf -)
fi
echo "[7/8] Generating hardware config"
hardware_file="/mnt/etc/nixos/hosts/${HOSTNAME}-hardware.nix"
echo "[6/7] Generating hardware config"
mkdir -p /mnt/etc/nixos/hosts
nixos-generate-config --root /mnt --show-hardware-config > "${hardware_file}"
if [[ "$USE_LUKS" -eq 1 || "${SWAP_GB}" -gt 0 ]]; then
tmpfile=$(mktemp)
# drop trailing closing brace
sed '$d' "${hardware_file}" > "${tmpfile}"
if [[ "$USE_LUKS" -eq 1 ]]; then
echo " boot.initrd.luks.devices.cryptroot.device = \"${part_root}\";" >> "${tmpfile}"
fi
if [[ "${SWAP_GB}" -gt 0 ]]; then
echo " swapDevices = [ { device = \"/swap/swapfile\"; } ];" >> "${tmpfile}"
fi
echo "}" >> "${tmpfile}"
mv "${tmpfile}" "${hardware_file}"
fi
nixos-generate-config --root /mnt --show-hardware-config > "/mnt/etc/nixos/hosts/${HOSTNAME}-hardware.nix"
host_file="/mnt/etc/nixos/hosts/${HOSTNAME}.nix"
if [ ! -e "${host_file}" ]; then
@ -226,9 +54,6 @@ if [ ! -e "${host_file}" ]; then
inputs.lix-module.nixosModules.lixFromNixpkgs
../modules/system/base.nix
../modules/users/admin.nix
# Uncomment to enable Secure Boot after install:
# inputs.lanzaboote.nixosModules.lanzaboote
# ../modules/system/secure-boot.nix
./${HOSTNAME}-hardware.nix
];
@ -237,7 +62,7 @@ if [ ! -e "${host_file}" ]; then
EOF
fi
echo "[8/8] Installing ${HOSTNAME} via flake"
echo "[7/7] Installing ${HOSTNAME} via flake"
nixos-install --root /mnt --flake "/mnt/etc/nixos#${HOSTNAME}"
echo "Install complete. You can reboot now."