diff options
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | README.org | 399 | ||||
| -rwxr-xr-x | build.sh | 4 | ||||
| -rwxr-xr-x | custom/install-archzfs | 127 | ||||
| -rw-r--r-- | custom/install-archzfs.conf.example | 77 | ||||
| -rw-r--r-- | docs/NOTES.org | 257 | ||||
| -rw-r--r-- | docs/session-context.org | 67 |
7 files changed, 876 insertions, 57 deletions
@@ -5,3 +5,5 @@ profile/ # Downloaded packages zfs-packages/ +vm/*.qcow2 +vm/OVMF_VARS.fd diff --git a/README.org b/README.org new file mode 100644 index 0000000..6a14d05 --- /dev/null +++ b/README.org @@ -0,0 +1,399 @@ +#+TITLE: archzfs - Arch Linux ZFS Root Installation ISO +#+AUTHOR: +#+OPTIONS: toc:3 + +* Overview + +archzfs is a custom Arch Linux ISO build system that creates a live environment +optimized for installing Arch Linux on ZFS root filesystems. It provides an +interactive installer with support for encrypted ZFS, multi-disk RAID +configurations, and automatic snapshot management. + +The ISO includes all necessary ZFS tools pre-loaded, eliminating the need for +manual module loading or package installation during the install process. + +* Features + +- *ZFS Root Filesystem* - Full ZFS installation with native encryption +- *Multi-Disk RAID* - Support for mirror, stripe, raidz1/2/3 configurations +- *EFI Boot Redundancy* - GRUB installed on all disks for boot resilience +- *fzf-Based Interface* - Fuzzy search for timezone, locale, keymap, disk, RAID, and WiFi selection +- *Genesis Snapshot* - Automatic pristine-state snapshot after installation +- *Rollback Script* - One-command factory reset via ~/root/rollback-to-genesis~ +- *Pre-Pacman Snapshots* - Automatic snapshots before package operations +- *NetworkManager* - WiFi configuration copied to installed system +- *SSH Ready* - Optional SSH with root login for headless servers +- *LTS Kernel* - Uses linux-lts for stability with ZFS + +* Quick Start + +#+BEGIN_SRC bash +# Build the ISO (requires root) +sudo ./build.sh + +# Test in a VM +./scripts/test-vm.sh + +# Or test with multiple disks for RAID +./scripts/test-vm.sh --multi-disk +#+END_SRC + +Boot the ISO and run ~install-archzfs~ to start the installation. + +* Prerequisites + +** Build Host Requirements +- Arch Linux (or Arch-based distribution) +- Root/sudo access +- ~archiso~ package installed (~pacman -S archiso~) +- ~10GB free disk space for build + +** Runtime Dependencies (included in ISO) +- ZFS kernel modules (via zfs-dkms) +- GRUB with ZFS support +- NetworkManager +- fzf for interactive selection + +* Building the ISO + +** Basic Build + +#+BEGIN_SRC bash +sudo ./build.sh +#+END_SRC + +The build script will: +1. Copy the base Arch releng profile +2. Switch to linux-lts kernel +3. Add the archzfs repository +4. Add custom packages (ZFS, NetworkManager, fzf, etc.) +5. Copy the install-archzfs script +6. Build the ISO using mkarchiso + +** Build Output + +- ISO location: ~out/archzfs-claude-YYYY.MM.DD-x86_64.iso~ +- Build logs: visible in terminal output +- Build time: typically 5-15 minutes depending on cache + +** Clean Rebuild + +#+BEGIN_SRC bash +sudo rm -rf work out +sudo ./build.sh +#+END_SRC + +* Project Structure + +#+BEGIN_EXAMPLE +archzfs/ +├── build.sh # Main ISO build script +├── custom/ +│ └── install-archzfs # Interactive installation script +├── scripts/ +│ └── test-vm.sh # QEMU test VM launcher +├── profile/ # archiso profile (generated during build) +│ ├── airootfs/ # Files copied to live ISO +│ │ └── usr/local/bin/ # Contains install-archzfs +│ ├── packages.x86_64 # Package list for ISO +│ └── pacman.conf # Pacman config with archzfs repo +├── vm/ # VM disk images (created by test-vm.sh) +├── work/ # Build working directory (created by build.sh) +├── out/ # Built ISO output (created by build.sh) +└── docs/ # Documentation +#+END_EXAMPLE + +** Script Descriptions + +| Script | Description | +|--------+-------------| +| ~build.sh~ | Builds the ISO. Copies releng profile, adds ZFS packages, configures kernel, runs mkarchiso | +| ~custom/install-archzfs~ | Interactive installer run on the live ISO. Handles disk partitioning, ZFS pool creation, base system install, bootloader setup | +| ~scripts/test-vm.sh~ | Launches QEMU VM for testing. Supports single and multi-disk configurations | + +* Testing with VMs + +** Basic VM Test + +#+BEGIN_SRC bash +./scripts/test-vm.sh +#+END_SRC + +This creates a 50GB virtual disk and boots the ISO. + +** Multi-Disk RAID Test + +#+BEGIN_SRC bash +# Two 50GB disks (for mirror or stripe) +./scripts/test-vm.sh --multi-disk + +# Three 50GB disks (for raidz1) +./scripts/test-vm.sh --multi-disk=3 +#+END_SRC + +** SSH Access to VM + +#+BEGIN_SRC bash +# Password: archzfs +ssh -p 2222 root@localhost + +# Or with sshpass +sshpass -p archzfs ssh -p 2222 root@localhost +#+END_SRC + +** Clean VM State + +#+BEGIN_SRC bash +./scripts/test-vm.sh --clean +#+END_SRC + +** Boot from Installed Disk + +#+BEGIN_SRC bash +./scripts/test-vm.sh --boot-disk +#+END_SRC + +* Development Workflow + +** Iterative Testing with Genesis Rollback + +After completing an installation in the VM, you can rollback to the genesis +snapshot and re-test without reinstalling. This is useful for testing archsetup +or other post-install scripts. + +*** In the VM (after installation and reboot): + +#+BEGIN_SRC bash +# Rollback to pristine post-install state +/root/rollback-to-genesis + +# Reboot to apply +reboot +#+END_SRC + +*** From the host: + +#+BEGIN_SRC bash +# The VM disk retains the ZFS pool +# Just boot from disk again +./scripts/test-vm.sh --boot-disk +#+END_SRC + +** Updating the Install Script + +#+BEGIN_SRC bash +# Edit the script +vim custom/install-archzfs + +# Copy to a running VM for immediate testing +sshpass -p archzfs scp -P 2222 custom/install-archzfs root@localhost:/usr/local/bin/ + +# Or rebuild the ISO for fresh testing +sudo ./build.sh +#+END_SRC + +* Installation Walkthrough + +The ~install-archzfs~ script provides a guided installation with fzf-based +selection interfaces. + +** Phase 1: Configuration Gathering + +1. *Hostname* - System hostname +2. *Timezone* - Fuzzy search through all timezones (preview shows current time) +3. *Locale* - All locales available (preview shows format examples) +4. *Keymap* - Console keyboard layout +5. *Disk Selection* - Multi-select with TAB (preview shows disk details) +6. *RAID Level* - For multi-disk: mirror, stripe, raidz1/2/3 (preview shows capacity calculations) +7. *WiFi* - Scan and select network (preview shows signal/security) +8. *ZFS Passphrase* - Encryption passphrase (required at every boot) +9. *Root Password* - System root password +10. *SSH* - Enable SSH with root login (default: yes) + +** Phase 2: Unattended Installation + +After configuration, the installation runs without intervention: +- Disk partitioning (EFI + ZFS on each disk) +- ZFS pool creation with encryption +- Dataset creation (ROOT, home, var, etc.) +- Base system installation via pacstrap +- System configuration (locale, timezone, hostname) +- Bootloader installation (GRUB on all EFI partitions) +- Genesis snapshot creation + +** RAID Level Options + +| Disks | Available Options | +|-------+-------------------| +| 1 | Single (no RAID) | +| 2 | Mirror, Stripe | +| 3+ | Mirror, Stripe, RAIDZ1 | +| 4+ | Mirror, Stripe, RAIDZ1, RAIDZ2 | +| 5+ | Mirror, Stripe, RAIDZ1, RAIDZ2, RAIDZ3 | + +* Bare Metal Installation + +** Preparing Installation Media + +#+BEGIN_SRC bash +# Write ISO to USB drive (replace /dev/sdX) +sudo dd if=out/archzfs-claude-*.iso of=/dev/sdX bs=4M status=progress oflag=sync +#+END_SRC + +** Booting + +1. Boot from USB (may need to disable Secure Boot) +2. Wait for live environment to load +3. Run ~install-archzfs~ + +** WiFi Setup + +The installer will scan for WiFi networks and present them in fzf. +Select your network and enter the password. The connection is tested +before proceeding and will be copied to the installed system. + +** SSH Access After Reboot + +If you enabled SSH during installation: +1. The system will have NetworkManager enabled +2. WiFi credentials are copied from the live environment +3. SSH is enabled with root password login +4. Connect via: ~ssh root@<ip-address>~ + +*Important*: Harden SSH after first login (disable password auth, use keys). + +** Post-Reboot Steps + +1. Enter ZFS encryption passphrase at boot +2. Log in as root +3. Run ~archsetup~ for further configuration + +* Post-Installation + +** Genesis Snapshot + +The installer creates a recursive snapshot of the entire pool named ~genesis~. +This represents the pristine post-install state. + +#+BEGIN_SRC bash +# View genesis snapshots +zfs list -t snapshot | grep genesis +#+END_SRC + +** Rollback to Factory State + +#+BEGIN_SRC bash +# Interactive rollback with confirmation +/root/rollback-to-genesis + +# Reboot to apply +reboot +#+END_SRC + +*Warning*: This destroys all changes since installation! + +** Useful ZFS Commands + +#+BEGIN_SRC bash +# List all snapshots +zfs list -t snapshot + +# Create manual snapshot +zfs snapshot zroot/home@my-backup + +# Rollback to snapshot +zfs rollback zroot/home@my-backup + +# Pool status +zpool status + +# Pool usage +zpool list +#+END_SRC + +* Keeping Up-to-Date + +** When to Rebuild + +Rebuild the ISO when: +- New Linux LTS kernel is released +- New ZFS version is released +- You've made changes to install-archzfs +- archzfs repository packages are updated + +** Rebuild Process + +#+BEGIN_SRC bash +# Clean and rebuild +sudo rm -rf work out +sudo ./build.sh +#+END_SRC + +The build automatically pulls the latest packages from: +- Official Arch repositories +- archzfs repository (https://archzfs.com) + +** Checking for Updates + +#+BEGIN_SRC bash +# Check current linux-lts version in repos +pacman -Si linux-lts | grep Version + +# Check archzfs package versions +curl -s https://archzfs.com/archzfs/x86_64/ | grep -o 'zfs-linux-lts-[^"]*' +#+END_SRC + +* Troubleshooting + +** Build Fails with Package Conflicts + +Clean the work directory and rebuild: +#+BEGIN_SRC bash +sudo rm -rf work +sudo ./build.sh +#+END_SRC + +** ZFS Module Not Loading + +The ISO includes DKMS-built ZFS modules. If modules fail to load: +- Check ~dmesg | grep -i zfs~ for errors +- Ensure you're using the LTS kernel +- The archzfs repo may be out of sync with kernel updates (wait for update) + +** Disk Not Showing in Selection + +- Ensure the disk is not mounted +- Check ~lsblk~ to verify disk visibility +- USB drives may need a moment to be detected + +** WiFi Networks Not Found + +- Verify WiFi hardware is present: ~ip link~ +- In VMs, there is no WiFi adapter (expected) +- Try rescanning: ~nmcli device wifi rescan~ + +** Boot Fails After Installation + +- Verify EFI boot entries: ~efibootmgr -v~ +- Check GRUB config: ~/boot/grub/grub.cfg~ +- Ensure ZFS modules in initramfs: ~lsinitcpio /boot/initramfs-linux-lts.img | grep zfs~ + +** Encryption Passphrase Not Accepted + +- Keyboard layout at boot is US by default +- Passphrase is case-sensitive +- Check for num-lock state + +* Links + +- [[https://archzfs.com][archzfs Repository]] - ZFS packages for Arch Linux +- [[https://openzfs.github.io/openzfs-docs/][OpenZFS Documentation]] - Official ZFS documentation +- [[https://wiki.archlinux.org/title/ZFS][Arch Wiki - ZFS]] - Arch-specific ZFS information +- [[https://wiki.archlinux.org/title/Archiso][Arch Wiki - Archiso]] - Building custom Arch ISOs +- [[https://github.com/openzfs/zfs][OpenZFS on GitHub]] - ZFS source code + +* License + +This project is licensed under the GNU General Public License v3.0 (GPL-3.0). + +See [[file:LICENSE][LICENSE]] file for the full license text. @@ -168,6 +168,10 @@ cp "$CUSTOM_DIR/install-archzfs" "$PROFILE_DIR/airootfs/usr/local/bin/" cp "$CUSTOM_DIR/install-claude" "$PROFILE_DIR/airootfs/usr/local/bin/" cp "$CUSTOM_DIR/archsetup-zfs" "$PROFILE_DIR/airootfs/usr/local/bin/" +# Copy example config for unattended installs +mkdir -p "$PROFILE_DIR/airootfs/root" +cp "$CUSTOM_DIR/install-archzfs.conf.example" "$PROFILE_DIR/airootfs/root/" + # Set permissions in profiledef.sh info "Setting file permissions..." if grep -q "file_permissions=" "$PROFILE_DIR/profiledef.sh"; then diff --git a/custom/install-archzfs b/custom/install-archzfs index 5f8b2a9..ae9e793 100755 --- a/custom/install-archzfs +++ b/custom/install-archzfs @@ -10,6 +10,11 @@ # - Optional WiFi configuration with connection test # - ZFS native encryption (passphrase required at boot) # - Pre-pacman ZFS snapshots for safe upgrades +# +# UNATTENDED MODE: +# Use --config-file /path/to/install-archzfs.conf for automated installs. +# Config file must be explicitly specified to prevent accidental disk wipes. +# See /root/install-archzfs.conf.example for a template with all options. set -e @@ -50,6 +55,72 @@ step() { echo ""; echo "==> $1"; } prompt() { echo "$1"; } ############################# +# Config File Support +############################# + +CONFIG_FILE="" +UNATTENDED=false + +parse_args() { + while [[ $# -gt 0 ]]; do + case "$1" in + --config-file) + if [[ -n "$2" && ! "$2" =~ ^- ]]; then + CONFIG_FILE="$2" + shift 2 + else + error "--config-file requires a path argument" + fi + ;; + --help|-h) + echo "Usage: install-archzfs [OPTIONS]" + echo "" + echo "Options:" + echo " --config-file PATH Use config file for unattended installation" + echo " --help, -h Show this help message" + echo "" + echo "Without --config-file, runs in interactive mode." + echo "See /root/install-archzfs.conf.example for a config template." + exit 0 + ;; + *) + error "Unknown option: $1 (use --help for usage)" + ;; + esac + done +} + +load_config() { + local config_path="$1" + + if [[ ! -f "$config_path" ]]; then + error "Config file not found: $config_path" + fi + + info "Loading config from: $config_path" + + # Source the config file (it's just key=value pairs) + # shellcheck disable=SC1090 + source "$config_path" + + # Convert DISKS from comma-separated string to array + if [[ -n "$DISKS" ]]; then + IFS=',' read -ra SELECTED_DISKS <<< "$DISKS" + fi + + UNATTENDED=true + info "Running in unattended mode" +} + +check_config() { + # Only use config when explicitly specified with --config-file + # This prevents accidental disk destruction from an unnoticed config file + if [[ -n "$CONFIG_FILE" ]]; then + load_config "$CONFIG_FILE" + fi +} + +############################# # Pre-flight Checks ############################# @@ -71,6 +142,37 @@ preflight_checks() { ############################# gather_input() { + if [[ "$UNATTENDED" == true ]]; then + # Validate required config values + [[ -z "$HOSTNAME" ]] && error "Config missing required: HOSTNAME" + [[ -z "$TIMEZONE" ]] && error "Config missing required: TIMEZONE" + [[ -z "$ZFS_PASSPHRASE" ]] && error "Config missing required: ZFS_PASSPHRASE" + [[ -z "$ROOT_PASSWORD" ]] && error "Config missing required: ROOT_PASSWORD" + [[ ${#SELECTED_DISKS[@]} -eq 0 ]] && error "Config missing required: DISKS" + + # Set defaults for optional values + [[ -z "$LOCALE" ]] && LOCALE="en_US.UTF-8" + [[ -z "$KEYMAP" ]] && KEYMAP="us" + [[ -z "$ENABLE_SSH" ]] && ENABLE_SSH="yes" + + # Determine RAID level if not specified + if [[ -z "$RAID_LEVEL" && ${#SELECTED_DISKS[@]} -gt 1 ]]; then + RAID_LEVEL="mirror" + info "Defaulting to mirror for ${#SELECTED_DISKS[@]} disks" + fi + + info "Configuration loaded:" + info " Hostname: $HOSTNAME" + info " Timezone: $TIMEZONE" + info " Locale: $LOCALE" + info " Keymap: $KEYMAP" + info " Disks: ${SELECTED_DISKS[*]}" + [[ -n "$RAID_LEVEL" ]] && info " RAID: $RAID_LEVEL" + info " SSH: $ENABLE_SSH" + [[ -n "$WIFI_SSID" ]] && info " WiFi: $WIFI_SSID" + return + fi + echo "" echo "╔═══════════════════════════════════════════════════════════════╗" echo "║ Arch Linux ZFS Root ║" @@ -731,7 +833,8 @@ EOF info "Installing base packages (this takes a while)..." info "ZFS will be built from source via DKMS - this ensures kernel compatibility." - pacstrap -K /mnt \ + # Use yes to auto-select defaults for provider prompts + yes "" | pacstrap -K /mnt \ base \ base-devel \ linux-lts \ @@ -843,7 +946,8 @@ configure_initramfs() { cp /mnt/etc/mkinitcpio.conf /mnt/etc/mkinitcpio.conf.bak # Configure hooks for ZFS - sed -i 's/^HOOKS=.*/HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block zfs filesystems fsck)/' /mnt/etc/mkinitcpio.conf + # ZFS doesn't use fsck - remove it to avoid confusing error messages + sed -i 's/^HOOKS=.*/HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block zfs filesystems)/' /mnt/etc/mkinitcpio.conf info "Regenerating initramfs..." arch-chroot /mnt mkinitcpio -P @@ -852,13 +956,17 @@ configure_initramfs() { configure_bootloader() { step "Configuring GRUB Bootloader" + # Get hostid for kernel parameter + local host_id + host_id=$(hostid) + # Configure GRUB defaults cat > /mnt/etc/default/grub << EOF GRUB_DEFAULT=0 GRUB_TIMEOUT=5 GRUB_DISTRIBUTOR="Arch Linux (ZFS)" -GRUB_CMDLINE_LINUX_DEFAULT="loglevel=3 quiet" -GRUB_CMDLINE_LINUX="root=ZFS=$POOL_NAME/ROOT/default" +GRUB_CMDLINE_LINUX_DEFAULT="loglevel=3" +GRUB_CMDLINE_LINUX="root=ZFS=$POOL_NAME/ROOT/default spl.spl_hostid=$host_id" GRUB_PRELOAD_MODULES="part_gpt part_msdos zfs" GRUB_TERMINAL_OUTPUT="console" GRUB_DISABLE_OS_PROBER=true @@ -912,6 +1020,15 @@ configure_zfs_services() { arch-chroot /mnt systemctl enable zfs-mount arch-chroot /mnt systemctl enable zfs-import.target + # Copy hostid to installed system (ZFS uses this for pool ownership) + if [[ -f /etc/hostid ]]; then + cp /etc/hostid /mnt/etc/hostid + else + # Generate hostid if it doesn't exist + zgenhostid + cp /etc/hostid /mnt/etc/hostid + fi + # Generate zpool cache mkdir -p /mnt/etc/zfs zpool set cachefile=/etc/zfs/zpool.cache "$POOL_NAME" @@ -1118,7 +1235,9 @@ print_summary() { ############################# main() { + parse_args "$@" preflight_checks + check_config gather_input # Unattended installation begins diff --git a/custom/install-archzfs.conf.example b/custom/install-archzfs.conf.example new file mode 100644 index 0000000..e97fe68 --- /dev/null +++ b/custom/install-archzfs.conf.example @@ -0,0 +1,77 @@ +# install-archzfs.conf - Unattended Installation Configuration +# +# Copy this file to /root/install-archzfs.conf and edit values. +# Or use: install-archzfs --config-file /path/to/your-config.conf +# +# Required fields: HOSTNAME, TIMEZONE, DISKS, ZFS_PASSPHRASE, ROOT_PASSWORD +# All other fields have sensible defaults. + +############################# +# System Configuration +############################# + +# Hostname for the installed system (required) +HOSTNAME=archzfs + +# Timezone (required) - Use format: Region/City +# Examples: America/Los_Angeles, Europe/London, Asia/Tokyo +TIMEZONE=America/Los_Angeles + +# Locale (optional, default: en_US.UTF-8) +LOCALE=en_US.UTF-8 + +# Console keymap (optional, default: us) +KEYMAP=us + +############################# +# Disk Configuration +############################# + +# Disks to use for installation (required) +# Single disk: DISKS=/dev/vda +# Multiple disks: DISKS=/dev/vda,/dev/vdb,/dev/vdc +DISKS=/dev/vda + +# RAID level for multi-disk setups (optional) +# Options: mirror, stripe, raidz1, raidz2, raidz3 +# Default: mirror (when multiple disks specified) +# Leave empty for single disk +RAID_LEVEL= + +############################# +# Security +############################# + +# ZFS encryption passphrase (required) +# This will be required at every boot to unlock the pool +ZFS_PASSPHRASE=changeme + +# Root password (required) +ROOT_PASSWORD=changeme + +############################# +# Network Configuration +############################# + +# Enable SSH with root login (optional, default: yes) +# Set to "no" to disable SSH +ENABLE_SSH=yes + +# WiFi configuration (optional) +# Leave empty for ethernet-only or to skip WiFi setup +WIFI_SSID= +WIFI_PASSWORD= + +############################# +# Advanced ZFS Options +############################# + +# Pool name (optional, default: zroot) +#POOL_NAME=zroot + +# Compression algorithm (optional, default: zstd) +#COMPRESSION=zstd + +# Sector size shift (optional, default: 12 for 4K sectors) +# Use 13 for 8K sector drives +#ASHIFT=12 diff --git a/docs/NOTES.org b/docs/NOTES.org index f56e7bd..89c02ad 100644 --- a/docs/NOTES.org +++ b/docs/NOTES.org @@ -1,6 +1,6 @@ -#+TITLE: Claude Code Notes - [Project Name] +#+TITLE: Claude Code Notes - archzfs #+AUTHOR: Craig Jennings & Claude -#+DATE: [Date] +#+DATE: 2026-01-17 * About This File @@ -22,50 +22,146 @@ This file contains project-specific information for this project. * Project-Specific Context -This is where context regarding this project is placed. - -Examples of what goes here: -- Project overview and goals -- People and their relationships to the user -- Contact information for companies and people -- Current state of the project -- Status report -- Links to important documents -- Technical architecture notes -- Key decisions and rationale - -** Welcome to Your First Session! - -This is your first session with Craig on this project. - -**First session checklist:** -1. **Determine project type and git/docs policy:** - - Is this project in a git repository? - - **Is this a code project** (Emacs package, library, software project)? - - **YES (code project):** Add docs/ to .gitignore (private notes, not part of codebase) - - Examples: org-msg, chime.el, wttrin, or any future Emacs packages/libraries - - docs/ contains session notes and should remain private - - **NO (non-code project):** Commit docs/ normally (part of the project documentation) - - Examples: personal projects, business planning, documentation projects - - docs/ is project documentation and should be versioned - - What are the remote repositories (if any)? - -2. **Understand the project:** - - Ask what the project is about - - Ask what the goals of the project are - - Ask any clarifying questions along the way - -3. **Brainstorm how to help:** - - Discuss approaches and strategies - - Identify immediate next steps - -4. **Document learnings:** - - Record what you learned in relevant sections of this document - - Add project-specific context below this section - -5. **Clean up:** - - Remove this "Welcome to Your First Session!" heading and its content - - Update Project-Specific Context section with actual project information +** Overview + +Build system for creating a custom Arch Linux installation ISO with ZFS support. The goal is to have a bootable ISO that can install Arch Linux on ZFS root without needing to manually compile ZFS or deal with kernel version mismatches. + +** Repository + +- Remote: =cjennings@cjennings.net:git/archzfs.git= +- Branch: =main= +- docs/ is committed (not private) + +** Key Components + +- =build.sh= - Main build script (runs as root) + - Downloads ZFS packages from archzfs GitHub releases + - Creates custom archiso profile based on releng + - Adds custom packages (nodejs, npm, jq, zsh, htop, ripgrep, etc.) + - Copies custom installer scripts into ISO + - Builds ISO with mkarchiso + +- =custom/= - Custom scripts included in ISO + - =install-archzfs= - Main installer script + - =install-claude= - Claude Code installer + - =archsetup-zfs= - ZFS-specific Arch setup + - =zfs-setup= - Installs ZFS packages and loads module (generated by build.sh) + +- =scripts/test-vm.sh= - QEMU VM for testing the ISO + +** Current State + +TESTING: install-archzfs script almost complete. + +- ISO builds successfully (4.8G) with linux-lts + zfs-dkms +- ZFS module loads correctly in live environment +- install-archzfs runs through partitioning, pool creation, base install, system config +- Last fix: added freetype2 for grub-mkfont (needs rebuild to test) + +Next: Rebuild ISO, complete install test, boot installed system. + +** Goals + +Create a bootable Arch Linux installation ISO that: +1. Installs Arch on ZFS root with native encryption +2. Uses sane defaults for dataset layout +3. Configures automatic snapshots (sanoid) +4. Sets up replication to TrueNAS for backups +5. Includes Claude Code on live ISO for emergency troubleshooting + +** Design Decisions + +*** Kernel Strategy +- Use =linux-lts= + =zfs-dkms= from archzfs.com repo +- DKMS builds ZFS from source, guaranteeing kernel compatibility +- Slower build time but eliminates version mismatch issues entirely +- LTS kernel provides stability, DKMS provides flexibility + +*** ZFS Pool Configuration +| Setting | Value | Rationale | +|---------+-------+-----------| +| Pool name | =zroot= | Standard convention | +| Encryption | AES-256-GCM, passphrase | Required at every boot | +| Compression | =zstd= (default) | Good balance of speed/ratio | +| Ashift | 12 (4K sectors) | Modern drives | +| Root reservation | 50GB | Prevents pool from filling | + +*** Dataset Layout +| Dataset | Mountpoint | Special Settings | Purpose | +|---------+------------+------------------+---------| +| zroot/ROOT/default | / | reservation=50G | Root filesystem | +| zroot/home | /home | | Home directories (archsetup creates user subdataset) | +| zroot/media | /media | compression=off | Pre-compressed media files | +| zroot/vms | /vms | recordsize=64K | VM disk images (qemu/libvirt + virtualbox) | +| zroot/var/log | /var/log | | System logs | +| zroot/var/cache | /var/cache | | Package cache | +| zroot/var/lib/pacman | /var/lib/pacman | | Package database | +| zroot/var/lib/docker | /var/lib/docker | | Docker storage | +| zroot/tmp | /tmp | auto-snapshot=false | Temp files | +| zroot/var/tmp | /var/tmp | auto-snapshot=false | Temp files | + +*** Snapshot Policy (Sanoid) +Less aggressive since TrueNAS handles long-term backups: + +| Template | Hourly | Daily | Weekly | Monthly | Used For | +|----------+--------+-------+--------+---------+----------| +| production | 6 | 7 | 2 | 1 | root, home, var/log, pacman | +| backup | 0 | 3 | 2 | 1 | media, vms | +| none | 0 | 0 | 0 | 0 | tmp, cache | + +Plus: Pacman hook creates snapshot before every transaction. + +*** TrueNAS Replication +- Primary: =truenas.local= (local network) +- Fallback: =truenas= (tailscale) +- Destination pool: =vault/[TBD]= +- Schedule: Nightly at 2:00 AM +- Datasets: ROOT/default, home, media, vms + +*** Included Packages +- Base system + development tools +- =nodejs=, =npm=, =jq= (for Claude Code) +- =zsh=, =htop=, =ripgrep=, =eza=, =fd=, =fzf= +- =sanoid= (snapshot management) +- =dialog= (installer UI) + +*** Installation UX +- All questions asked upfront, then unattended installation +- WiFi tested before installation begins (if provided) +- User can walk away during install and come back +- Summary + final confirmation before starting + +*** User Account Strategy +- install-archzfs creates root account only (asks for root password) +- No user account created during install +- Just create =zroot/home= dataset (no user-specific subdataset) +- archsetup creates user account + home dataset post-reboot + +*** GRUB HiDPI Support +- Generate 32px DejaVuSansMono font during install +- Set =GRUB_FONT= to use custom font +- Works well on HiDPI and regular displays + +*** WiFi Configuration +- Ask for SSID + password during install (optional) +- Test connection before installation starts +- Copy connection profile to installed system +- Auto-connects after reboot + +*** Post-Install Workflow +1. install-archzfs: Minimal ZFS system + root account +2. Reboot, login as root +3. Run archsetup manually for full workstation setup + +*** Testing/Debugging (VM) +- SSH access on live ISO: sshd enabled, known root password +- Serial console: =-serial mon:stdio= in QEMU for terminal copy/paste +- Port forwarding: 2222→22 (already configured) +- Allows easy copy/paste of error messages during testing + +** Open Questions + +- [ ] TrueNAS destination dataset path (vault/???) * AVAILABLE WORKFLOWS @@ -233,15 +329,70 @@ Each entry should use this format: ** Session Entries -*** [First session date] +*** 2026-01-17 Sat @ 17:10 -0600 -*Time:* Initial setup -*Status:* COMPLETE - Template created +*Status:* IN PROGRESS *What We Completed:* -- Project initialized with Claude Code templates -- Ready for first work session +- Fixed ZFS kernel module mismatch by switching to linux-lts + zfs-dkms +- Fixed bootloader to use linux-lts kernel (was defaulting to regular linux) +- Fixed broadcom-wl dependency (switched to broadcom-wl-dkms) +- Updated mkinitcpio preset for linux-lts with archiso config +- Fixed install-archzfs bugs: + - =[[ ]] && error= pattern causing early exit with =set -e= (changed to if/then) + - 50G reservation on 50G disk (now dynamic: 20% of pool, capped 5-20G) + - sanoid not in official repos (moved to archsetup) + - grub-mkfont needs freetype2 package (added to pacstrap) +- Removed sanoid/syncoid from install-archzfs (archsetup will handle) +- Created inbox item for archsetup with full sanoid/syncoid config +- ISO now 4.8G (was 5.4G) - only linux-lts kernel + +*Key Technical Insights:* +- =broadcom-wl= depends on =linux= kernel specifically - use =broadcom-wl-dkms= instead +- archiso releng profile has linux.preset in airootfs that needs renaming to linux-lts.preset +- With =set -e=, =[[ test ]] && command= returns exit code 1 if test is false, causing script exit +- =grub-mkfont= requires =freetype2= package (not installed by default with grub) + +*Files Modified:* +- [[file:../build.sh][build.sh]] - major updates for linux-lts, bootloader configs, mkinitcpio preset +- [[file:../custom/install-archzfs][custom/install-archzfs]] - multiple bug fixes, removed sanoid/syncoid +- [[file:~/code/archsetup/inbox/zfs-sanoid-detection.txt][archsetup inbox]] - sanoid/syncoid config for archsetup to implement + +*Current State:* +- ISO builds successfully with linux-lts + zfs-dkms +- ZFS module loads correctly in live environment +- install-archzfs runs through most steps +- Last error: grub-mkfont missing freetype2 (now fixed, needs rebuild/test) *Next Steps:* -- Begin first actual work session -- Follow "Welcome to Your First Session!" checklist above +- Rebuild ISO with freetype2 fix +- Complete full install-archzfs test in VM +- Test booting the installed system +- Git commit all changes + +*** 2026-01-17 Sat @ 13:16 -0600 + +*Status:* COMPLETE (continued above) + +*What We Completed:* +- Initialized git repository +- Created .gitignore (excludes work/, out/, profile/, zfs-packages/) +- Initial commit with all build scripts +- Added docs/ to git (decided to track publicly) +- Built fresh ISO (archzfs-claude-2026.01.17-x86_64.iso, 4.9G) +- Tested ISO in QEMU VM +- Documented project goals and design decisions in NOTES.org + +*Key Decisions Made:* +- Use linux-lts + zfs-dkms from archzfs.com (DKMS ensures kernel compatibility) +- Less aggressive snapshot policy (TrueNAS handles long-term backups) +- All install questions upfront, then unattended installation +- Root account only (archsetup creates user post-reboot) +- 32px GRUB font for HiDPI displays +- WiFi config tested before install starts + +*Files Modified:* +- [[file:../.gitignore][.gitignore]] - created +- [[file:../build.sh][build.sh]] - major rewrite +- [[file:../custom/install-archzfs][custom/install-archzfs]] - complete rewrite +- [[file:../scripts/test-vm.sh][scripts/test-vm.sh]] - added serial console diff --git a/docs/session-context.org b/docs/session-context.org new file mode 100644 index 0000000..5274ae3 --- /dev/null +++ b/docs/session-context.org @@ -0,0 +1,67 @@ +#+TITLE: Session Context - archzfs +#+DATE: 2026-01-18 + +* Current Session State + +** What We're Working On +Testing unattended installation with --config-file option. Currently running 2-disk mirror test. + +** Key Progress This Session + +*** Config File Support for Unattended Installs +- Added --config-file /path/to/config argument +- Config only used when explicitly specified (prevents accidental disk wipes) +- Example config at /root/install-archzfs.conf.example on ISO +- Validates required fields: HOSTNAME, TIMEZONE, DISKS, ZFS_PASSPHRASE, ROOT_PASSWORD +- Sets sensible defaults for optional fields + +*** Boot Fixes for ZFS +- Removed fsck from mkinitcpio HOOKS (ZFS doesn't use fsck) +- Added hostid generation/copy to installed system +- Added spl.spl_hostid to kernel command line +- Removed 'quiet' from kernel params for visible boot messages + +*** Multi-Disk RAID Support +- RAID level selection: mirror, stripe, raidz1/2/3 +- EFI partitions on all disks for boot redundancy +- Stripe option for max capacity (no redundancy) +- Dynamic capacity calculations in preview + +*** fzf-Based User Interface +- Replaced all select menus with fzf fuzzy finder +- Timezone: fuzzy search with current time preview +- Locale: all locales shown, format examples in preview +- Keymap: all keymaps with layout info +- Disk selection: multi-select (TAB), disk details preview +- RAID level: explanatory preview with capacity calculations +- WiFi: network list by signal strength, security info preview + +*** Documentation +- Created comprehensive README.org (15 sections) +- TODO.org with project tasks + +** Files Modified This Session +- custom/install-archzfs - Config file support, boot fixes +- custom/install-archzfs.conf.example - NEW: template for unattended installs +- build.sh - Copies example config to ISO +- README.org - Comprehensive documentation +- TODO.org - Project task tracking + +** Bugs Being Investigated +- Install script exiting early in unattended mode - FIXED with return 0 +- Still need to verify full installation completes and boots successfully + +** Testing Status +- Test 1: 2-disk mirror - IN PROGRESS (packages installing) +- Test 2: 2-disk stripe - PENDING +- Test 3: Single disk - PENDING + +** Test Configuration +- VM: ./scripts/test-vm.sh --multi-disk +- SSH: sshpass -p archzfs ssh -p 2222 root@localhost +- Config file: /root/test-mirror.conf + +** Test Credentials +- Live ISO root password: archzfs +- Test ZFS passphrase: testpass123 +- Test root password: testpass123 |
