Major ISO build overhaul on dev-iso branch: - Replace ~800MB Debian Live download with debootstrap --variant=minbase (~150MB installer squashfs built from scratch) - Custom initramfs with archipelago-mount hook for boot media detection - Systemd service auto-starts installer (replaces profile.d hack) - GRUB + ISOLINUX configs written from scratch (no Debian Live dependency) - EFI boot image built with grub-mkimage (no more MBR extraction) - Archipelago GRUB theme: dark background, Bitcoin orange accents - Theme installed on both installer ISO and target system - Rootfs optimizations: --no-install-recommends, strip docs/man/locales, remove firmware-misc-nonfree/wget/htop, add explicit font deps - Separate CI workflow (build-iso-dev.yml) for dev-iso branch - Includes pre-existing fixes from main (build-iso.yml, middleware, Login) Target: sub-2GB unbundled ISO (down from 3.9GB) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
9.4 KiB
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.
- Branch from current
main - 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-binto tool dependencies - Output naming:
archipelago-dev-unbundled-{date}.iso
- Keep: backend build, frontend build, type check, tests, build report
- Trigger:
- 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-nonfreefrom 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):
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) andhtop(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 hookfilesystem.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:
- Scans
/dev/sr0,/dev/sd*for a partition containingarchipelago/auto-install.sh - Mounts it read-only at
/run/archiso - This replaces Debian Live's
boot=live componentsmechanism
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(fromisolinuxpackage) - 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:
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) highlightbackground.png— 1920x1080 dark with subtle Archipelago logo watermark- Font files (
.pf2) — generated withgrub-mkfontfrom 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
- Phase 0 — branch + CI (~1 hour)
- Phase 1 — rootfs size opts (~2 hours, push + verify)
- Phase 2 — custom base (~8-10 hours, iterative QEMU testing)
- 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 |