# ISO Overhaul: Custom Minimal Base + Branding + Size Optimization ## Context The Archipelago ISO is ~3.9GB — too large. The root cause is a ~800MB Debian Live ISO used as the boot base, plus a ~2.1GB rootfs with no `--no-install-recommends`. We're replacing the Debian Live dependency entirely with a custom debootstrap-built installer, adding full Archipelago branding to the boot chain, and stripping the rootfs. Target: sub-2GB ISO. All work on `dev-iso` branch with its own CI workflow. Main branch stays untouched. --- ## Phase 0: Branch + CI Setup **Create `dev-iso` branch and separate CI workflow.** 1. Branch from current `main` 2. Create `.gitea/workflows/build-iso-dev.yml`: - Trigger: `push: branches: [dev-iso]` + `workflow_dispatch` - Same structure as `build-iso.yml` (131 lines) but: - Remove "Cache Debian Live ISO" step (no longer needed) - Add `debootstrap`, `squashfs-tools`, `isolinux`, `syslinux-common`, `mtools`, `grub-efi-amd64-bin`, `grub-pc-bin` to tool dependencies - Output naming: `archipelago-dev-unbundled-{date}.iso` - Keep: backend build, frontend build, type check, tests, build report 3. Push and verify CI triggers on .228 runner **Files:** - New: `.gitea/workflows/build-iso-dev.yml` --- ## Phase 1: Rootfs Size Optimizations **Shrink rootfs.tar from ~2.1GB to ~1.5GB. Only touches the Dockerfile heredoc in Step 1 (lines 210-335).** ### 1.1 Add `--no-install-recommends` - Line 229: `apt-get install -y` → `apt-get install -y --no-install-recommends` - Line 269: Same for Tailscale install - Explicitly add packages that may be needed as recommends: `fonts-liberation`, `xfonts-base` (for Chromium kiosk) - **Saves: ~150-300MB** ### 1.2 Remove `firmware-misc-nonfree` - Line 257: Remove `firmware-misc-nonfree` from package list - Keep: `firmware-realtek`, `firmware-iwlwifi`, `intel-microcode`, `amd64-microcode` - **Saves: ~50-80MB** ### 1.3 Strip docs/man/locales - Add after line 264 (after apt-get clean): ```dockerfile RUN find /usr/share/doc -depth -type f ! -name copyright -delete 2>/dev/null; \ find /usr/share/doc -empty -delete 2>/dev/null; \ rm -rf /usr/share/man /usr/share/info /usr/share/lintian /usr/share/linda; \ find /usr/share/locale -maxdepth 1 -mindepth 1 ! -name 'en_US' ! -name 'locale.alias' -exec rm -rf {} + ``` - **Saves: ~50-80MB** ### 1.4 Remove `wget` and `htop` - Lines 244, 246: Remove `wget` (curl covers it) and `htop` (luxury tool) - Keep `git` (used by self-update system) - **Saves: ~5MB** (minor but removes unnecessary surface) ### Verification - Build ISO, compare rootfs.tar size - Boot in QEMU, verify: kiosk renders, SSH works, nginx serves UI, podman runs **Files modified:** - `image-recipe/build-auto-installer-iso.sh` (Step 1 Dockerfile heredoc, lines 210-335) --- ## Phase 2: Replace Debian Live with Custom Debootstrap Base **The big one. Replaces Steps 2, 5, and parts of 4 and 6.** ### 2.1 New Step 2: Build Minimal Installer Environment Replace lines 420-502 entirely. Run debootstrap inside a container to produce: - `vmlinuz` — kernel (reused from linux-image-amd64) - `initrd.img` — custom initramfs with ISO-mount hook - `filesystem.squashfs` — minimal Debian root (~120-180MB) The installer squashfs contains only what's needed to run the auto-install script: - `debootstrap --variant=minbase --include=systemd,systemd-sysv,udev,bash,coreutils,mount,util-linux,cryptsetup,parted,dosfstools,e2fsprogs,kmod,procps,iproute2,ca-certificates,gdisk` - Auto-login on tty1 via getty override - systemd service that auto-starts the installer (replaces profile.d hack) **Key: Custom initramfs hook** (`local-bottom/archipelago-mount`) that: 1. Scans `/dev/sr0`, `/dev/sd*` for a partition containing `archipelago/auto-install.sh` 2. Mounts it read-only at `/run/archiso` 3. This replaces Debian Live's `boot=live components` mechanism ### 2.2 New Step 5: Assemble ISO Directory Replace lines 2236-2448 entirely. Much simpler — no squashfs overlay mechanism, no tools extraction (tools are in the squashfs), no profile.d manipulation. New Step 5 just assembles the directory structure: ``` $INSTALLER_ISO/ live/ vmlinuz initrd.img filesystem.squashfs boot/grub/ grub.cfg themes/archipelago/ (Phase 3) efi.img (built with grub-mkimage) isolinux/ isolinux.bin ldlinux.c32 isolinux.cfg EFI/BOOT/ BOOTX64.EFI (built with grub-mkimage) archipelago/ auto-install.sh rootfs.tar bin/archipelago web-ui/ scripts/ container-images/ (if bundled) ``` Generate EFI boot image with `grub-mkimage` and ISOLINUX files from the `isolinux` package. No more extracting MBR from Debian Live. ### 2.3 Updated Step 6: ISO Creation Replace lines 2461-2511 (MBR extraction + EFI image search). Use: - MBR: `/usr/lib/ISOLINUX/isohdpfx.bin` (from `isolinux` package) - EFI: `boot/grub/efi.img` (built in Step 5) - xorriso command stays the same structure ### 2.4 Update Boot Media Paths in Step 4 (auto-install.sh) Lines 1154-1155: Add `/run/archiso` as first search path: ```bash for dev in /run/archiso /cdrom /media/cdrom /run/live/medium /lib/live/mount/medium; do ``` Also update lines 2326, 2377 (no longer needed — replaced by systemd service in installer squashfs). ### 2.5 Remove Debian Live cleanup from auto-install.sh The installed system's auto-install script currently removes `live-boot`, `live-boot-initramfs-tools`, `live-config` (around line 1872). With the custom base, these packages won't exist in the rootfs, so this cleanup becomes a harmless no-op — but should be cleaned up for clarity. ### Verification - Build ISO, verify size < 2GB - Boot in QEMU (UEFI mode): verify GRUB menu → installer → full install → reboot - Boot in QEMU (BIOS mode): verify ISOLINUX → installer → full install → reboot - After install: SSH, web UI, kiosk, container loading all work - Test `test-iso-qemu.sh` (may need minor path updates) **Files modified:** - `image-recipe/build-auto-installer-iso.sh` (Steps 2, 4, 5, 6 — major rewrite) --- ## Phase 3: Archipelago Boot Branding **Custom GRUB theme, installer banner, installed system GRUB.** ### 3.1 Create GRUB Theme New directory: `image-recipe/branding/grub-theme/` - `theme.txt` — dark background (#0a0a0a), white text, Bitcoin orange (#f7931a) highlight - `background.png` — 1920x1080 dark with subtle Archipelago logo watermark - Font files (`.pf2`) — generated with `grub-mkfont` from DejaVu Sans during build GRUB menu entries: - "Install Archipelago" (default, quiet boot) - "Install Archipelago (verbose)" (no `quiet`, for debugging) - "Boot from local disk" (chainloader) ### 3.2 Create ISOLINUX Theme New file: `image-recipe/branding/isolinux.cfg` - Matching dark theme for legacy BIOS boot - Same menu entries as GRUB ### 3.3 Branded Installer Banner The systemd service's start script displays: ``` ARCHIPELAGO BITCOIN NODE OS Automatic Installer v0.1.0 Press Enter to start installation... ``` ### 3.4 Install GRUB Theme to Target System In Step 4 (auto-install.sh), before `update-grub` (around line 1888): - Copy GRUB theme from ISO to `/mnt/target/boot/grub/themes/archipelago/` - Add `GRUB_THEME="/boot/grub/themes/archipelago/theme.txt"` to `/mnt/target/etc/default/grub` - The installed system boots with Archipelago branding, not Debian default ### 3.5 Create Background Image Render from existing SVG favicon (`neode-ui/public/assets/icon/favico-black-v2.svg`) to PNG at appropriate sizes. Dark background with subtle centered logo. ### Verification - Boot ISO: GRUB shows Archipelago theme (dark + orange) - No Debian branding visible anywhere - After install: target system GRUB also shows Archipelago theme **Files:** - New: `image-recipe/branding/grub-theme/theme.txt` - New: `image-recipe/branding/grub-theme/background.png` - New: `image-recipe/branding/isolinux.cfg` - Modified: `image-recipe/build-auto-installer-iso.sh` (Steps 5, 4) --- ## Risk Areas | Risk | Severity | Mitigation | |------|----------|------------| | Custom initramfs fails to find USB media | High | Test multiple USB controller types in QEMU; add verbose fallback boot option | | Missing packages in minbase break install | Medium | Trace auto-install.sh dependencies; test full install flow | | GRUB EFI image missing modules | High | Include all common modules in grub-mkimage; test UEFI + BIOS | | Kiosk breaks without recommends | Medium | Explicitly add Chromium/X11 font deps; test kiosk before merge | | initramfs overlayfs mount fails | High | Follow well-established patterns from Arch/Ubuntu live ISOs | --- ## Implementation Order 1. **Phase 0** — branch + CI (~1 hour) 2. **Phase 1** — rootfs size opts (~2 hours, push + verify) 3. **Phase 2** — custom base (~8-10 hours, iterative QEMU testing) 4. **Phase 3** — branding (~3 hours) Phases are sequential — each builds on the previous. Push after each phase, verify CI passes. --- ## Key Files | File | Role | |------|------| | `image-recipe/build-auto-installer-iso.sh` | Main build script — most changes here | | `.gitea/workflows/build-iso-dev.yml` | New CI workflow for dev-iso branch | | `image-recipe/branding/grub-theme/*` | New GRUB theme assets | | `image-recipe/branding/isolinux.cfg` | New ISOLINUX config | | `image-recipe/test-iso-qemu.sh` | QEMU test script (minor updates) | | `.gitea/workflows/build-iso.yml` | Reference for new CI workflow | | `scripts/image-versions.sh` | Unchanged — container image versions |