From d6491d8c38c2ff03c358127b61ff2ae51dc14a0a Mon Sep 17 00:00:00 2001 From: Brandon Lucas Date: Sun, 15 Feb 2026 04:24:20 -0500 Subject: [PATCH] Add fresh install script for ISO installer - Add installer/fresh-install.sh for installing from live ISO - Handles disk partitioning, LUKS encryption, filesystem setup - Generates minimal NixOS config for first boot - Enable flakes in ISO environment - Pass installer script content to ISO build via specialArgs Co-Authored-By: Claude Opus 4.5 --- .gitignore | 1 + flake.nix | 5 +- installer/fresh-install.sh | 452 +++++++++++++++++++++++++++++++++++++ iso/default.nix | 22 +- 4 files changed, 465 insertions(+), 15 deletions(-) create mode 100755 installer/fresh-install.sh diff --git a/.gitignore b/.gitignore index 21681cc..79a48cf 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ Thumbs.db # Local user config (generated by installer) config.local.nix +test-vm/ diff --git a/flake.nix b/flake.nix index 35ede9e..fe15a86 100644 --- a/flake.nix +++ b/flake.nix @@ -105,7 +105,10 @@ # ISO installer configuration installer = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; - specialArgs = {inherit inputs;}; + specialArgs = { + inherit inputs; + installerScriptContent = builtins.readFile ./installer/fresh-install.sh; + }; modules = [ ./iso/default.nix ]; diff --git a/installer/fresh-install.sh b/installer/fresh-install.sh new file mode 100755 index 0000000..a8c4855 --- /dev/null +++ b/installer/fresh-install.sh @@ -0,0 +1,452 @@ +#!/usr/bin/env bash +# Nomarchy Fresh Installation Script +# For use from the live ISO to install on a new disk + +set -euo pipefail + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +NC='\033[0m' +BOLD='\033[1m' + +# Installation target +TARGET_DISK="" +USE_LUKS=true +LUKS_PARTITION="" +ROOT_PARTITION="" +EFI_PARTITION="" + +print_banner() { + echo -e "${CYAN}" + cat << 'EOF' + _ __ __ + / | / /___ ____ ___ ____ _____/ /___ __ + / |/ / __ \/ __ `__ \/ __ `/ __/ / __/ / / + / /| / /_/ / / / / / / /_/ / / / / /__ / / +/_/ |_/\____/_/ /_/ /_/\__,_/_/ /_/\___//_/ + + Fresh Installation +EOF + echo -e "${NC}" + echo "" +} + +check_root() { + if [ "$(id -u)" != "0" ]; then + echo -e "${RED}Error: This installer must be run as root.${NC}" + echo "Run: sudo nomarchy-fresh-install" + exit 1 + fi +} + +check_uefi() { + if [ ! -d /sys/firmware/efi ]; then + echo -e "${YELLOW}Warning: System is not booted in UEFI mode.${NC}" + echo "Nomarchy requires UEFI. Please reboot in UEFI mode." + read -rp "Continue anyway (legacy BIOS)? [y/N]: " cont + if [[ ! "$cont" =~ ^[Yy] ]]; then + exit 1 + fi + else + echo -e "${GREEN}UEFI mode detected.${NC}" + fi +} + +list_disks() { + echo -e "${BOLD}Available disks:${NC}" + echo "" + lsblk -d -o NAME,SIZE,MODEL,TYPE | grep -E "disk|NAME" + echo "" +} + +select_disk() { + list_disks + + echo -e "${YELLOW}WARNING: The selected disk will be completely erased!${NC}" + echo "" + read -rp "Enter disk to install to (e.g., sda, vda, nvme0n1): " disk_input + + if [ -z "$disk_input" ]; then + echo -e "${RED}No disk selected. Aborting.${NC}" + exit 1 + fi + + # Handle nvme vs sata naming + if [[ "$disk_input" == nvme* ]]; then + TARGET_DISK="/dev/${disk_input}" + EFI_PARTITION="${TARGET_DISK}p1" + ROOT_PARTITION="${TARGET_DISK}p2" + else + TARGET_DISK="/dev/${disk_input}" + EFI_PARTITION="${TARGET_DISK}1" + ROOT_PARTITION="${TARGET_DISK}2" + fi + + if [ ! -b "$TARGET_DISK" ]; then + echo -e "${RED}Error: ${TARGET_DISK} is not a valid block device.${NC}" + exit 1 + fi + + echo "" + echo -e "${RED}${BOLD}WARNING: ALL DATA ON ${TARGET_DISK} WILL BE DESTROYED!${NC}" + echo "" + read -rp "Type 'yes' to confirm: " confirm + + if [ "$confirm" != "yes" ]; then + echo "Aborting." + exit 1 + fi +} + +prompt_encryption() { + echo "" + echo -e "${BOLD}Disk Encryption${NC}" + echo "LUKS encryption protects your data if the device is lost or stolen." + read -rp "Enable LUKS encryption? [Y/n]: " luks_choice + luks_choice="${luks_choice:-y}" + + if [[ "$luks_choice" =~ ^[Yy] ]]; then + USE_LUKS=true + echo -e "${GREEN}LUKS encryption enabled.${NC}" + else + USE_LUKS=false + echo -e "${YELLOW}Installing without encryption.${NC}" + fi + echo "" +} + +partition_disk() { + echo -e "${BLUE}Partitioning ${TARGET_DISK}...${NC}" + + # Wipe existing partition table + wipefs -a "$TARGET_DISK" + + # Create GPT partition table with EFI and root partitions + parted -s "$TARGET_DISK" mklabel gpt + parted -s "$TARGET_DISK" mkpart ESP fat32 1MiB 512MiB + parted -s "$TARGET_DISK" set 1 esp on + parted -s "$TARGET_DISK" mkpart primary 512MiB 100% + + # Wait for partitions to appear + sleep 2 + partprobe "$TARGET_DISK" + sleep 1 + + echo -e "${GREEN}Partitioning complete.${NC}" +} + +setup_luks() { + if [ "$USE_LUKS" = true ]; then + echo "" + echo -e "${BLUE}Setting up LUKS encryption...${NC}" + echo -e "${YELLOW}You will be prompted to enter a passphrase.${NC}" + echo "" + + cryptsetup luksFormat --type luks2 "$ROOT_PARTITION" + cryptsetup open "$ROOT_PARTITION" cryptroot + + LUKS_PARTITION="$ROOT_PARTITION" + ROOT_PARTITION="/dev/mapper/cryptroot" + + echo -e "${GREEN}LUKS encryption configured.${NC}" + fi +} + +format_filesystems() { + echo "" + echo -e "${BLUE}Formatting filesystems...${NC}" + + # Format EFI partition + mkfs.fat -F32 "$EFI_PARTITION" + + # Format root partition with ext4 + mkfs.ext4 -L nixos "$ROOT_PARTITION" + + echo -e "${GREEN}Filesystems formatted.${NC}" +} + +mount_filesystems() { + echo "" + echo -e "${BLUE}Mounting filesystems...${NC}" + + mount "$ROOT_PARTITION" /mnt + mkdir -p /mnt/boot + mount "$EFI_PARTITION" /mnt/boot + + echo -e "${GREEN}Filesystems mounted.${NC}" +} + +generate_hardware_config() { + echo "" + echo -e "${BLUE}Generating hardware configuration...${NC}" + + nixos-generate-config --root /mnt + + echo -e "${GREEN}Hardware configuration generated.${NC}" +} + +# User configuration prompts (similar to install.sh) +prompt_username() { + echo "" + echo -e "${BOLD}Username${NC}" + read -rp "Enter username: " username + username="${username:-user}" +} + +prompt_hostname() { + echo "" + echo -e "${BOLD}Hostname${NC}" + read -rp "Enter hostname: " hostname_input + hostname_input="${hostname_input:-nomarchy}" +} + +prompt_timezone() { + echo "" + echo -e "${BOLD}Timezone${NC}" + echo "Examples: America/New_York, Europe/London, Asia/Tokyo" + read -rp "Enter timezone [UTC]: " timezone + timezone="${timezone:-UTC}" +} + +prompt_locale() { + echo "" + echo -e "${BOLD}Locale${NC}" + read -rp "Enter locale [en_US.UTF-8]: " locale + locale="${locale:-en_US.UTF-8}" +} + +prompt_keyboard() { + echo "" + echo -e "${BOLD}Keyboard Layout${NC}" + read -rp "Enter keyboard layout [us]: " keyboard + keyboard="${keyboard:-us}" +} + +prompt_bootloader() { + echo "" + echo -e "${BOLD}Bootloader${NC}" + echo "1) systemd-boot - Simple, reliable" + echo "2) Limine - Modern, themed to match Nomarchy" + read -rp "Choose bootloader [1/2]: " bootloader_choice + bootloader_choice="${bootloader_choice:-1}" + + if [[ "$bootloader_choice" == "2" ]]; then + bootloader="limine" + else + bootloader="systemd-boot" + fi +} + +prompt_features() { + echo "" + echo -e "${BOLD}Optional Features${NC}" + + read -rp "Enable Plymouth boot splash? [y/N]: " plymouth + [[ "$plymouth" =~ ^[Yy] ]] && enable_plymouth="true" || enable_plymouth="false" + + read -rp "Enable Syncthing? [Y/n]: " syncthing + syncthing="${syncthing:-y}" + [[ "$syncthing" =~ ^[Yy] ]] && enable_syncthing="true" || enable_syncthing="false" + + read -rp "Enable printing support? [Y/n]: " printing + printing="${printing:-y}" + [[ "$printing" =~ ^[Yy] ]] && enable_printing="true" || enable_printing="false" +} + +generate_config() { + echo "" + echo -e "${BLUE}Generating Nomarchy configuration...${NC}" + + local config_dir="/mnt/etc/nomarchy" + mkdir -p "$config_dir" + + # Keyboard layouts as Nix list + local kb_layouts_nix + kb_layouts_nix=$(echo "$keyboard" | sed 's/,/" "/g' | sed 's/^/"/' | sed 's/$/"/') + + cat > "$config_dir/config.nix" << EOF +# Nomarchy Configuration +# Generated during installation on $(date) +{ + username = "${username}"; + hostname = "${hostname_input}"; + timezone = "${timezone}"; + locale = "${locale}"; + keyboardLayouts = [${kb_layouts_nix}]; + keyboardVariants = [""]; + + location = { + lat = 0; + lon = 0; + }; + + enableSyncthing = ${enable_syncthing}; + enableMullvad = false; + enablePrinting = ${enable_printing}; + enableBluetooth = true; + + bootloader = "${bootloader}"; + enablePlymouth = ${enable_plymouth}; + + enableMitigationsOff = false; + + theme = "classical"; +} +EOF + + # Generate flake.nix + cat > "$config_dir/flake.nix" << 'FLAKEEOF' +{ + description = "Nomarchy NixOS Configuration"; + + inputs = { + nomarchy.url = "github:blu/nomarchy"; + nixpkgs.follows = "nomarchy/nixpkgs"; + }; + + outputs = { self, nomarchy, nixpkgs, ... }@inputs: let + userConfig = import ./config.nix; + in { + nixosConfigurations.${userConfig.hostname} = nomarchy.lib.mkHost { + system = "x86_64-linux"; + config = userConfig; + extraModules = [ + /etc/nixos/hardware-configuration.nix + ]; + }; + }; +} +FLAKEEOF + + # Build LUKS config if needed + local luks_config="" + if [ "$USE_LUKS" = true ]; then + local luks_uuid + luks_uuid=$(blkid -s UUID -o value "$LUKS_PARTITION") + luks_config=" + # LUKS encryption + boot.initrd.luks.devices.\"cryptroot\" = { + device = \"/dev/disk/by-uuid/${luks_uuid}\"; + preLVM = true; + };" + fi + + # Create configuration.nix with LUKS config included + cat > "/mnt/etc/nixos/configuration.nix" << EOF +# This file is managed by Nomarchy +# Edit /etc/nomarchy/config.nix instead +{ ... }: { + imports = [ ./hardware-configuration.nix ]; + + # Minimal config for initial boot - will be replaced by flake + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + + networking.hostName = "${hostname_input}"; + time.timeZone = "${timezone}"; + + users.users.${username} = { + isNormalUser = true; + extraGroups = [ "wheel" "networkmanager" ]; + initialPassword = "changeme"; + }; + + services.openssh.enable = true; + networking.networkmanager.enable = true; +${luks_config} + system.stateVersion = "24.11"; +} +EOF + + echo -e "${GREEN}Configuration generated.${NC}" +} + +run_install() { + echo "" + echo -e "${BLUE}Installing NixOS...${NC}" + echo "This may take a while." + echo "" + + NIX_CONFIG="experimental-features = nix-command flakes" nixos-install --no-root-passwd + + echo "" + echo -e "${GREEN}Installation complete!${NC}" +} + +set_user_password() { + echo "" + echo -e "${BOLD}Set password for ${username}${NC}" + nixos-enter --root /mnt -c "passwd ${username}" +} + +show_summary() { + echo "" + echo -e "${BOLD}Installation Summary${NC}" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo -e "Disk: ${CYAN}${TARGET_DISK}${NC}" + echo -e "Encryption: ${CYAN}${USE_LUKS}${NC}" + echo -e "Username: ${CYAN}${username}${NC}" + echo -e "Hostname: ${CYAN}${hostname_input}${NC}" + echo -e "Timezone: ${CYAN}${timezone}${NC}" + echo -e "Bootloader: ${CYAN}${bootloader}${NC}" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "" +} + +finish() { + echo "" + echo -e "${GREEN}${BOLD}Nomarchy installation complete!${NC}" + echo "" + echo "Next steps:" + echo " 1. Reboot: shutdown -r now" + echo " 2. Log in as '${username}' with the password you set" + echo " 3. Select 'Hyprland' from the session menu" + echo " 4. Press Super+/ for Quick Actions" + echo "" + echo "To rebuild with flake (after first boot):" + echo " cd /etc/nomarchy && sudo nixos-rebuild switch --flake .#${hostname_input}" + echo "" +} + +main() { + print_banner + check_root + check_uefi + + select_disk + prompt_encryption + partition_disk + setup_luks + format_filesystems + mount_filesystems + generate_hardware_config + + # User configuration + prompt_username + prompt_hostname + prompt_timezone + prompt_locale + prompt_keyboard + prompt_bootloader + prompt_features + + show_summary + + read -rp "Proceed with installation? [Y/n]: " proceed + proceed="${proceed:-y}" + if [[ ! "$proceed" =~ ^[Yy] ]]; then + echo "Installation cancelled." + exit 0 + fi + + generate_config + run_install + set_user_password + finish +} + +main "$@" diff --git a/iso/default.nix b/iso/default.nix index ddb57da..cd27f9e 100644 --- a/iso/default.nix +++ b/iso/default.nix @@ -5,6 +5,7 @@ pkgs, modulesPath, inputs, + installerScriptContent, ... }: { imports = [ @@ -68,6 +69,9 @@ # NixOS installation nixos-install-tools + + # Nomarchy installer script + (writeShellScriptBin "nomarchy-install" installerScriptContent) ]; # Auto-login to installer @@ -80,7 +84,7 @@ ║ ║ ║ Welcome to the Nomarchy Installer ║ ║ ║ - ║ Run 'nomarchy-install' to begin installation ║ + ║ Run 'sudo nomarchy-install' to begin installation ║ ║ ║ ║ For more information: https://github.com/blu/nomarchy ║ ║ ║ @@ -88,19 +92,6 @@ ''; - # Copy installer script - system.activationScripts.installer = '' - mkdir -p /usr/local/bin - cat > /usr/local/bin/nomarchy-install << 'INSTALLER' - #!/usr/bin/env bash - # Nomarchy ISO Installer - coming soon - echo "ISO installer not yet implemented." - echo "Please use the NixOS manual installation process," - echo "then run: nix run github:blu/nomarchy" - INSTALLER - chmod +x /usr/local/bin/nomarchy-install - ''; - # User account users.users.nixos = { isNormalUser = true; @@ -111,6 +102,9 @@ # Allow passwordless sudo security.sudo.wheelNeedsPassword = false; + # Enable flakes + nix.settings.experimental-features = ["nix-command" "flakes"]; + # System state version system.stateVersion = "24.11"; }