archy/.claude/plans/silly-wondering-flamingo.md
Dorian 7183ebfa2b feat: replace Debian Live with custom debootstrap ISO base + branding
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>
2026-03-28 11:34:29 +00:00

244 lines
9.4 KiB
Markdown

# 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 |