# Archiso — Custom Live Installer The archiso build system produces a bootable Arch Linux ISO pre-loaded with the M-Archy installer scripts. Optionally, an answerfile can be embedded so the entire install — base OS + dotfiles — runs with zero user interaction. --- ## Prerequisites ```bash sudo pacman -S archiso jq ``` --- ## Building the ISO ```bash # Basic build — interactive installer, no answerfile bash setup/archiso/build.sh # Specify output directory bash setup/archiso/build.sh /path/to/output # Embed an answerfile for automated deployment bash setup/archiso/build.sh --preconf # Embed a specific answerfile bash setup/archiso/build.sh --preconf ~/my-server.json # Both flags together bash setup/archiso/build.sh --preconf ~/my-server.json /media/usb/output ``` | Flag | Effect | |------|--------| | _(none)_ | Clean ISO, no answerfile | | `--preconf` | Embed `~/answerfile.json` at `/answerfile.json` in the ISO | | `--preconf FILE` | Embed the specified file instead | Build artefacts land in `~/m-archy-out/` by default. Override with the `OUT_DIR` environment variable or by passing a path argument. ### Environment Variables | Variable | Default | Purpose | |----------|---------|---------| | `WORK_DIR` | `~/m-archy-build` | Scratch space for mkarchiso | | `OUT_DIR` | `~/m-archy-out` | ISO output directory | --- ## What the Build Does 1. Copies the upstream `releng` Arch base profile 2. Applies the M-Archy overlay (`setup/archiso/overlay/`) 3. Replaces `profiledef.sh` with the M-Archy version 4. Adds extra packages from `packages.extra` 5. Embeds both installer scripts (`arch-autoinstall.sh`, `archbaseos-guided-install.sh`) into `/root/installer/` 6. If `--preconf`: copies the answerfile to `/answerfile.json` in the ISO's airootfs 7. Runs `mkarchiso` to produce the final `.iso` --- ## Extra Packages on the Live System Defined in `setup/archiso/overlay/packages.extra`: ``` git jq pam-u2f btop fastfetch openssh libfido2 ``` `libfido2` is included to support FIDO2 / token-based LUKS unlock in the system reset mode (see below). These are added on top of the standard Arch `releng` package set. --- ## Live System Entry Points Once booted from the ISO, the following are available: ### `install-arch` A command placed in `/usr/local/bin/`: ```bash install-arch # guided mode (default) install-arch guided # guided interactive install install-arch auto # automated mode (reads /answerfile.json) ``` ### `/root/launch.sh` Internal dispatcher used by `install-arch`. After keymap selection, it prompts for one of two actions: - **Install** — runs the normal guided or automated installer. - **Reset** — runs `setup/reset-arch.sh` (see [System Reset Mode](#system-reset-mode)). ### `/answerfile.json` Only present when built with `--preconf`. Both installer scripts check for this file on startup. If found, all prompts are answered from it — the only interaction required is the disk-encryption password (passwords are never stored in answerfiles). --- ## System Reset Mode `setup/reset-arch.sh` performs a non-destructive system reinstall from the live environment, keeping user home data and authentication keys intact. ### What it does 1. Detects LUKS2 encryption on the selected partition and unlocks it: - **Option 1** (recommended): tries the enrolled FIDO2/TPM2 token first, falls back to passphrase. - **Option 2**: passphrase only. - **Option 3**: enrolled token only. 2. Snapshots `/etc` credentials and config from the existing `@` subvolume. 3. Wipes `~/.config` from `@home` for all users, **preserving** `~/.config/Yubico/` so FIDO2 PAM login continues to work after reset. 4. Deletes and recreates the `@` (root) Btrfs subvolume. 5. Reinstalls base system packages via `pacstrap`. 6. Restores `passwd`, `shadow`, `pam.d`, `sudoers`, `fstab`, `mkinitcpio.conf`, and GRUB config from the snapshot. 7. Regenerates initramfs and GRUB menu from chroot. ### How to run it Boot from the ISO. At the action prompt, select **Reset**. The reset mode is also available standalone on any live Arch environment: ```bash bash /path/to/setup/reset-arch.sh ``` ### What is preserved | Data | Preserved | |------|-----------| | User home directories (`/home/*`) | Yes | | User passwords (`/etc/shadow`) | Yes | | FIDO2 keys (`~/.config/Yubico/`) | Yes | | PAM configuration | Yes | | sudoers rules | Yes | | fstab, mkinitcpio config | Yes | | App configs (`~/.config/*`) | **No** (wiped except Yubico) | | Installed packages | **No** (reinstalled from base) | --- ## Automated Deployment Workflow ``` ┌─────────────────────────────────────┐ │ Developer machine │ │ │ │ 1. generate-answerfile.sh │ │ → ~/answerfile.json │ │ │ │ 2. build.sh --preconf │ │ → ~/m-archy-out/m-archy.iso │ │ │ │ 3. dd if=m-archy.iso of=/dev/sdX │ └──────────────┬──────────────────────┘ │ USB ▼ ┌─────────────────────────────────────┐ │ Target machine (boots from USB) │ │ │ │ 4. install-arch auto │ │ reads /answerfile.json │ │ installs base OS │ │ runs tui-install.sh in chroot │ │ installs dotfiles & apps │ │ │ │ 5. Reboot → ready system │ └─────────────────────────────────────┘ ``` For multi-machine deployments, the `hostname` field in the answerfile is combined with the machine's MAC address, so each system gets a unique hostname even though they share the same answerfile. --- ## Overlay Structure ``` setup/archiso/overlay/ ├── airootfs/ │ ├── etc/motd # Welcome message │ ├── root/ │ │ └── launch.sh # Installer entry point │ └── usr/local/bin/ │ └── install-arch # User-facing CLI command ├── packages.extra # Additional live-system packages └── profiledef.sh # M-Archy ISO profile definition ``` The `build.sh` script also adds at build time: ``` airootfs/root/installer/ ├── arch-autoinstall.sh └── archbaseos-guided-install.sh ``` --- ## Writing the ISO to USB ```bash # Find the USB drive lsblk # Write (replace /dev/sdX with your drive — ALL DATA WILL BE ERASED) sudo dd if=~/m-archy-out/m-archy-*.iso of=/dev/sdX bs=4M status=progress oflag=sync ``` Or use `ventoy` / `balenaEtcher` as alternatives. --- ## PXE Boot / netboot.xyz Every build also produces a `*-netboot-*.tar.gz` artifact alongside the ISO. This tarball contains the kernel, initrd, and squashfs image laid out for HTTP-based PXE booting. The live initramfs already includes the `archiso_pxe_http` hook, so no extra packages or custom kernel parameters beyond the ones below are required. ### 1. Build with a netboot URL ```bash bash setup/archiso/build.sh --netboot-url http://your-server/m-archy # or combined with an answerfile: bash setup/archiso/build.sh --preconf --netboot-url http://your-server/m-archy ``` This generates `~/m-archy-out/m-archy-netboot.ipxe` alongside the netboot tarball. ### 2. Serve the artifacts Extract the netboot tarball so that its contents are reachable at the base URL you provided: ```bash # On your web server mkdir -p /srv/http/m-archy tar -xzf ~/m-archy-out/*-netboot-*.tar.gz -C /srv/http/m-archy cp ~/m-archy-out/m-archy-netboot.ipxe /srv/http/m-archy/ ``` The server must expose at minimum: ``` http://your-server/m-archy/arch/boot/x86_64/vmlinuz-linux http://your-server/m-archy/arch/boot/x86_64/initramfs-linux.img http://your-server/m-archy/arch/x86_64/airootfs.sfs http://your-server/m-archy/m-archy-netboot.ipxe ``` ### 3. Add to netboot.xyz In your netboot.xyz configuration (or the **Custom iPXE** option in the netboot.xyz menu), chainload the generated script: ``` chain http://your-server/m-archy/m-archy-netboot.ipxe ``` Or add a named menu item: ``` item m-archy M-Archy Arch Linux Installer ... :m-archy chain http://your-server/m-archy/m-archy-netboot.ipxe ``` ### Manual iPXE parameters If you prefer to write the boot stanza by hand (e.g. for a self-hosted netboot.xyz with YAML menus): ``` kernel http://your-server/m-archy/arch/boot/x86_64/vmlinuz-linux \ archiso_http_srv=http://your-server/m-archy/ \ archisobasedir=arch \ ip=dhcp initrd http://your-server/m-archy/arch/boot/x86_64/initramfs-linux.img boot ``` | Kernel parameter | Purpose | |-----------------|---------| | `archiso_http_srv=/` | Base URL the initramfs fetches the squashfs from (trailing slash required) | | `archisobasedir=arch` | Subdirectory prefix — matches `install_dir` in `profiledef.sh` | | `ip=dhcp` | Acquire an IP before the HTTP fetch |