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>
This commit is contained in:
parent
018f3c84d3
commit
4326f019c1
243
.claude/plans/silly-wondering-flamingo.md
Normal file
243
.claude/plans/silly-wondering-flamingo.md
Normal file
@ -0,0 +1,243 @@
|
||||
# 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 |
|
||||
128
.gitea/workflows/build-iso-dev.yml
Normal file
128
.gitea/workflows/build-iso-dev.yml
Normal file
@ -0,0 +1,128 @@
|
||||
name: Build Archipelago ISO (dev)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [dev-iso]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-iso:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
clean: false
|
||||
|
||||
- name: Install ISO build dependencies
|
||||
run: |
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -y -qq \
|
||||
debootstrap squashfs-tools xorriso \
|
||||
isolinux syslinux-common mtools \
|
||||
grub-efi-amd64-bin grub-pc-bin grub-common
|
||||
|
||||
- name: Build backend
|
||||
run: |
|
||||
source $HOME/.cargo/env 2>/dev/null || true
|
||||
cargo build --release --manifest-path core/Cargo.toml
|
||||
|
||||
- name: Build frontend
|
||||
run: cd neode-ui && npm ci && npm run build
|
||||
|
||||
- name: Type check frontend
|
||||
run: cd neode-ui && npx vue-tsc -b --noEmit
|
||||
|
||||
- name: Run frontend tests
|
||||
run: cd neode-ui && npx vitest run
|
||||
|
||||
- name: Configure root podman for insecure registry
|
||||
run: |
|
||||
sudo mkdir -p /etc/containers/registries.conf.d
|
||||
echo '[[registry]]
|
||||
location = "80.71.235.15:3000"
|
||||
insecure = true' | sudo tee /etc/containers/registries.conf.d/archipelago.conf
|
||||
|
||||
- name: Build unbundled ISO
|
||||
run: |
|
||||
cd image-recipe
|
||||
export ARCHIPELAGO_BIN="$(pwd)/../core/target/release/archipelago"
|
||||
ls -la "$ARCHIPELAGO_BIN" || echo "WARNING: binary not found"
|
||||
sudo -E UNBUNDLED=1 DEV_SERVER=localhost BUILD_FROM_SOURCE=0 \
|
||||
ARCHIPELAGO_BIN="$ARCHIPELAGO_BIN" \
|
||||
./build-auto-installer-iso.sh
|
||||
|
||||
- name: Copy to Builds
|
||||
run: |
|
||||
ISO=$(ls image-recipe/results/archipelago-installer-unbundled-*.iso 2>/dev/null | head -1)
|
||||
if [ -n "$ISO" ]; then
|
||||
DATE=$(date +%Y%m%d-%H%M)
|
||||
DEST="/var/lib/archipelago/filebrowser/Builds/archipelago-dev-unbundled-${DATE}.iso"
|
||||
sudo cp "$ISO" "$DEST"
|
||||
sudo chown 1000:1000 "$DEST"
|
||||
echo "ISO: archipelago-dev-unbundled-${DATE}.iso"
|
||||
echo "Size: $(du -h "$DEST" | cut -f1)"
|
||||
echo "SHA256: $(sha256sum "$DEST" | cut -d' ' -f1)"
|
||||
fi
|
||||
|
||||
- name: Build report
|
||||
if: always()
|
||||
continue-on-error: true
|
||||
run: |
|
||||
set +eo pipefail
|
||||
echo "══════════════════════════════════════════"
|
||||
echo "DEV ISO BUILD REPORT"
|
||||
echo "══════════════════════════════════════════"
|
||||
echo "Commit: $(git rev-parse --short HEAD) ($(git log -1 --format=%s))"
|
||||
echo "Branch: ${GITHUB_REF_NAME:-dev-iso}"
|
||||
echo "Date: $(date -u '+%Y-%m-%d %H:%M:%S UTC')"
|
||||
echo "Runner: $(hostname)"
|
||||
echo ""
|
||||
echo "── Artifacts ──"
|
||||
ls -lh image-recipe/results/*.iso 2>/dev/null || echo " No ISO produced"
|
||||
ls -lh /var/lib/archipelago/filebrowser/Builds/archipelago-dev-*.iso 2>/dev/null | tail -3
|
||||
echo ""
|
||||
echo "── Rootfs contents check ──"
|
||||
ROOTFS=$(ls image-recipe/build/auto-installer/archipelago-rootfs.tar 2>/dev/null) || true
|
||||
if [ -n "$ROOTFS" ]; then
|
||||
echo " rootfs.tar: $(sudo du -h "$ROOTFS" 2>/dev/null | cut -f1 || echo 'unknown')"
|
||||
echo " nginx config: $(sudo tar tf "$ROOTFS" ./etc/nginx/sites-available/archipelago 2>/dev/null && echo 'PRESENT' || echo 'MISSING')"
|
||||
echo " SSL cert: $(sudo tar tf "$ROOTFS" ./etc/archipelago/ssl/archipelago.crt 2>/dev/null && echo 'PRESENT' || echo 'MISSING')"
|
||||
echo " kiosk launcher: $(sudo tar tf "$ROOTFS" ./usr/local/bin/archipelago-kiosk-launcher 2>/dev/null && echo 'PRESENT' || echo 'MISSING')"
|
||||
echo " backend binary: $(sudo tar tf "$ROOTFS" ./usr/local/bin/archipelago 2>/dev/null && echo 'PRESENT' || echo 'MISSING')"
|
||||
echo " web-ui index: $(sudo tar tf "$ROOTFS" ./opt/archipelago/web-ui/index.html 2>/dev/null && echo 'PRESENT' || echo 'MISSING')"
|
||||
else
|
||||
echo " rootfs.tar not found in workspace"
|
||||
fi
|
||||
echo ""
|
||||
echo "── ISO contents check ──"
|
||||
ISO=$(ls image-recipe/results/archipelago-installer-unbundled-*.iso 2>/dev/null | head -1) || true
|
||||
if [ -n "$ISO" ]; then
|
||||
echo " ISO size: $(sudo du -h "$ISO" 2>/dev/null | cut -f1 || echo 'unknown')"
|
||||
ISO_MOUNT=$(mktemp -d)
|
||||
if sudo mount -o loop,ro "$ISO" "$ISO_MOUNT" 2>/dev/null; then
|
||||
echo " auto-install.sh: $([ -f "$ISO_MOUNT/archipelago/auto-install.sh" ] && echo 'PRESENT' || echo 'MISSING')"
|
||||
echo " rootfs.tar: $([ -f "$ISO_MOUNT/archipelago/rootfs.tar" ] && echo "PRESENT ($(sudo du -h "$ISO_MOUNT/archipelago/rootfs.tar" 2>/dev/null | cut -f1))" || echo 'MISSING')"
|
||||
echo " backend bin: $([ -f "$ISO_MOUNT/archipelago/bin/archipelago" ] && echo "PRESENT ($(sudo du -h "$ISO_MOUNT/archipelago/bin/archipelago" 2>/dev/null | cut -f1))" || echo 'MISSING')"
|
||||
echo " frontend: $([ -f "$ISO_MOUNT/archipelago/web-ui/index.html" ] && echo 'PRESENT' || echo 'MISSING')"
|
||||
echo " vmlinuz: $([ -f "$ISO_MOUNT/live/vmlinuz" ] && echo 'PRESENT' || echo 'MISSING')"
|
||||
echo " initrd: $([ -f "$ISO_MOUNT/live/initrd.img" ] && echo 'PRESENT' || echo 'MISSING')"
|
||||
echo " squashfs: $([ -f "$ISO_MOUNT/live/filesystem.squashfs" ] && echo "PRESENT ($(sudo du -h "$ISO_MOUNT/live/filesystem.squashfs" 2>/dev/null | cut -f1))" || echo 'MISSING')"
|
||||
echo " grub theme: $([ -d "$ISO_MOUNT/boot/grub/themes/archipelago" ] && echo 'PRESENT' || echo 'MISSING')"
|
||||
sudo umount "$ISO_MOUNT" 2>/dev/null || true
|
||||
else
|
||||
echo " Could not mount ISO for inspection"
|
||||
fi
|
||||
rmdir "$ISO_MOUNT" 2>/dev/null || true
|
||||
fi
|
||||
echo "══════════════════════════════════════════"
|
||||
|
||||
- name: Fix workspace permissions
|
||||
if: always()
|
||||
run: |
|
||||
sudo chown -R $(id -u):$(id -g) . 2>/dev/null || true
|
||||
sudo chmod -R u+rwX . 2>/dev/null || true
|
||||
sudo chown -R $(id -u):$(id -g) "$HOME/.cache/act" 2>/dev/null || true
|
||||
sudo chmod -R u+rwX "$HOME/.cache/act" 2>/dev/null || true
|
||||
52
image-recipe/branding/grub-theme/theme.txt
Normal file
52
image-recipe/branding/grub-theme/theme.txt
Normal file
@ -0,0 +1,52 @@
|
||||
# Archipelago GRUB Theme
|
||||
# Dark background with Bitcoin orange accents
|
||||
|
||||
title-text: ""
|
||||
desktop-color: "#0a0a0a"
|
||||
terminal-font: "DejaVu Sans Regular 16"
|
||||
|
||||
+ boot_menu {
|
||||
left = 25%
|
||||
top = 40%
|
||||
width = 50%
|
||||
height = 30%
|
||||
item_font = "DejaVu Sans Regular 16"
|
||||
item_color = "#aaaaaa"
|
||||
selected_item_font = "DejaVu Sans Regular 16"
|
||||
selected_item_color = "#ffffff"
|
||||
selected_item_pixmap_style = "select_*.png"
|
||||
item_height = 36
|
||||
item_spacing = 8
|
||||
item_padding = 16
|
||||
scrollbar = false
|
||||
}
|
||||
|
||||
+ label {
|
||||
left = 25%
|
||||
top = 20%
|
||||
width = 50%
|
||||
text = "A R C H I P E L A G O"
|
||||
font = "DejaVu Sans Bold 24"
|
||||
color = "#f7931a"
|
||||
align = "center"
|
||||
}
|
||||
|
||||
+ label {
|
||||
left = 25%
|
||||
top = 28%
|
||||
width = 50%
|
||||
text = "Bitcoin Node OS"
|
||||
font = "DejaVu Sans Regular 14"
|
||||
color = "#888888"
|
||||
align = "center"
|
||||
}
|
||||
|
||||
+ label {
|
||||
left = 25%
|
||||
top = 90%
|
||||
width = 50%
|
||||
text = "Use arrow keys to select, Enter to boot"
|
||||
font = "DejaVu Sans Regular 12"
|
||||
color = "#555555"
|
||||
align = "center"
|
||||
}
|
||||
@ -31,7 +31,7 @@
|
||||
# build-auto-installer-iso.sh — Main orchestrator (config, CLI args, step sequencing)
|
||||
# lib/
|
||||
# rootfs.sh — Step 1: Build root filesystem via Docker (~185 lines)
|
||||
# installer-env.sh — Step 2: Download/extract Debian Live base ISO (~80 lines)
|
||||
# installer-env.sh — Step 2: Build minimal installer via debootstrap (~80 lines)
|
||||
# components.sh — Step 3: Add Archipelago components (binary, configs, web UI) (~120 lines)
|
||||
# container-images.sh — Step 3b: Bundle container images for offline install (~330 lines)
|
||||
# auto-install-script.sh — Step 4: Generate the embedded auto-install.sh (~615 lines)
|
||||
@ -133,25 +133,31 @@ check_tools() {
|
||||
missing="$missing docker-or-podman"
|
||||
fi
|
||||
|
||||
if ! command -v xorriso >/dev/null 2>&1; then
|
||||
missing="$missing xorriso"
|
||||
for tool in xorriso mksquashfs; do
|
||||
if ! command -v $tool >/dev/null 2>&1; then
|
||||
missing="$missing $tool"
|
||||
fi
|
||||
if ! command -v 7z >/dev/null 2>&1 && ! command -v 7za >/dev/null 2>&1; then
|
||||
missing="$missing p7zip-full"
|
||||
done
|
||||
# Check for isolinux MBR (needed for hybrid USB boot)
|
||||
if [ ! -f /usr/lib/ISOLINUX/isohdpfx.bin ] && [ ! -f /usr/share/syslinux/isohdpfx.bin ]; then
|
||||
missing="$missing isolinux"
|
||||
fi
|
||||
|
||||
if [ -n "$missing" ]; then
|
||||
echo "❌ Missing required tools:$missing"
|
||||
echo "Missing required tools:$missing"
|
||||
|
||||
if [ "$can_install" = true ]; then
|
||||
echo " 📦 Auto-installing missing dependencies..."
|
||||
echo " Auto-installing missing dependencies..."
|
||||
apt-get update -qq
|
||||
|
||||
if [[ "$missing" == *"xorriso"* ]]; then
|
||||
apt-get install -y xorriso
|
||||
fi
|
||||
if [[ "$missing" == *"p7zip-full"* ]]; then
|
||||
apt-get install -y p7zip-full
|
||||
if [[ "$missing" == *"mksquashfs"* ]]; then
|
||||
apt-get install -y squashfs-tools
|
||||
fi
|
||||
if [[ "$missing" == *"isolinux"* ]]; then
|
||||
apt-get install -y isolinux syslinux-common
|
||||
fi
|
||||
|
||||
if [[ "$missing" == *"docker-or-podman"* ]]; then
|
||||
@ -160,9 +166,9 @@ check_tools() {
|
||||
CONTAINER_CMD="podman"
|
||||
fi
|
||||
|
||||
echo " ✅ Dependencies installed successfully!"
|
||||
echo " Dependencies installed successfully!"
|
||||
else
|
||||
echo " Install with: sudo apt install xorriso podman"
|
||||
echo " Install with: sudo apt install xorriso squashfs-tools isolinux podman"
|
||||
echo " Or run this script with sudo to auto-install"
|
||||
exit 1
|
||||
fi
|
||||
@ -226,7 +232,7 @@ RUN echo "deb http://deb.debian.org/debian bookworm main non-free-firmware" > /e
|
||||
rm -f /etc/apt/sources.list.d/debian.sources
|
||||
|
||||
# Install all packages we need including nginx, podman, tor, and openssl (for self-signed certs)
|
||||
RUN apt-get update && apt-get install -y \
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
${LINUX_IMAGE_PKG} \
|
||||
${GRUB_EFI_PKG} \
|
||||
${GRUB_EFI_SIGNED_PKG} \
|
||||
@ -241,9 +247,7 @@ RUN apt-get update && apt-get install -y \
|
||||
podman \
|
||||
tor \
|
||||
curl \
|
||||
wget \
|
||||
git \
|
||||
htop \
|
||||
vim-tiny \
|
||||
ca-certificates \
|
||||
openssl \
|
||||
@ -254,19 +258,26 @@ RUN apt-get update && apt-get install -y \
|
||||
cryptsetup \
|
||||
firmware-realtek \
|
||||
firmware-iwlwifi \
|
||||
firmware-misc-nonfree \
|
||||
intel-microcode \
|
||||
amd64-microcode \
|
||||
xorg \
|
||||
chromium \
|
||||
unclutter \
|
||||
fonts-liberation \
|
||||
xfonts-base \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Strip docs, man pages, and unused locales
|
||||
RUN find /usr/share/doc -depth -type f ! -name copyright -delete 2>/dev/null || true && \
|
||||
find /usr/share/doc -empty -delete 2>/dev/null || true && \
|
||||
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 {} + 2>/dev/null || true
|
||||
|
||||
# Install Tailscale from official repo
|
||||
RUN curl -fsSL https://pkgs.tailscale.com/stable/debian/bookworm.noarmor.gpg | tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null && \
|
||||
curl -fsSL https://pkgs.tailscale.com/stable/debian/bookworm.tailscale-keyring.list | tee /etc/apt/sources.list.d/tailscale.list && \
|
||||
apt-get update && apt-get install -y tailscale && \
|
||||
apt-get update && apt-get install -y --no-install-recommends tailscale && \
|
||||
apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Configure locale
|
||||
@ -418,88 +429,249 @@ else
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# STEP 2: Create installer environment
|
||||
# STEP 2: Build minimal installer environment (replaces Debian Live)
|
||||
# =============================================================================
|
||||
echo ""
|
||||
echo "📦 Step 2: Creating installer environment..."
|
||||
echo "Step 2: Building minimal installer environment via debootstrap..."
|
||||
|
||||
# Download Debian Live as our installer base
|
||||
BASE_ISO="$WORK_DIR/debian-live-installer.iso"
|
||||
EXPECTED_SIZE=350000000 # ~350MB min (Debian 12 Live standard ~600MB)
|
||||
|
||||
# Check if file exists and is complete
|
||||
if [ -f "$BASE_ISO" ]; then
|
||||
CURRENT_SIZE=$(stat -f%z "$BASE_ISO" 2>/dev/null || stat -c%s "$BASE_ISO" 2>/dev/null || echo 0)
|
||||
if [ "$CURRENT_SIZE" -ge "$EXPECTED_SIZE" ]; then
|
||||
echo " ✅ Debian Live base already downloaded"
|
||||
else
|
||||
echo " Found incomplete download ($(($CURRENT_SIZE / 1024 / 1024))MB), removing..."
|
||||
rm -f "$BASE_ISO"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -f "$BASE_ISO" ]; then
|
||||
echo " Downloading Debian Live base (352MB)..."
|
||||
echo " (This may take 5-10 minutes depending on network speed)"
|
||||
|
||||
# Use wget without -O so --continue actually works
|
||||
# Download with the ugly SourceForge filename, then rename
|
||||
# Use Debian 12 (Bookworm) to match the rootfs — NOT Debian 13 (Trixie)
|
||||
ISO_URL="https://cdimage.debian.org/cdimage/archive/12.10.0-live/${DEB_ARCH}/iso-hybrid/debian-live-12.10.0-${DEB_ARCH}-standard.iso"
|
||||
|
||||
if command -v wget >/dev/null 2>&1; then
|
||||
cd "$WORK_DIR"
|
||||
wget --tries=10 --read-timeout=120 --continue --progress=bar:force \
|
||||
--no-check-certificate \
|
||||
"$ISO_URL" || {
|
||||
echo " ❌ Download failed or incomplete"
|
||||
echo " Partial file kept - run script again to continue"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Find the downloaded file — wget may use URL filename or follow redirects
|
||||
FOUND_ISO=$(find "$WORK_DIR" -maxdepth 1 -name "debian-live-12*.iso" -o -name "download" 2>/dev/null | head -1)
|
||||
if [ -n "$FOUND_ISO" ] && [ -f "$FOUND_ISO" ]; then
|
||||
mv "$FOUND_ISO" "$BASE_ISO"
|
||||
else
|
||||
echo " ❌ Downloaded file not found in $WORK_DIR"
|
||||
echo " Files present:"
|
||||
ls -la "$WORK_DIR"/*.iso 2>/dev/null || echo " (no .iso files)"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# Fallback to curl (no resume support)
|
||||
curl -L --location-trusted --retry 10 --retry-delay 5 \
|
||||
--connect-timeout 60 --max-time 1800 \
|
||||
-o "$BASE_ISO" \
|
||||
"$ISO_URL" || {
|
||||
echo " ❌ Download failed"
|
||||
rm -f "$BASE_ISO"
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
|
||||
# Verify download size
|
||||
FINAL_SIZE=$(stat -f%z "$BASE_ISO" 2>/dev/null || stat -c%s "$BASE_ISO" 2>/dev/null || echo 0)
|
||||
if [ "$FINAL_SIZE" -lt "$EXPECTED_SIZE" ]; then
|
||||
echo " ❌ Download incomplete: got $(($FINAL_SIZE / 1024 / 1024))MB, expected 352MB"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo " ✅ Download complete ($(($FINAL_SIZE / 1024 / 1024))MB)"
|
||||
fi
|
||||
|
||||
echo " Extracting installer base..."
|
||||
INSTALLER_ISO="$WORK_DIR/installer-iso"
|
||||
rm -rf "$INSTALLER_ISO"
|
||||
mkdir -p "$INSTALLER_ISO"
|
||||
cd "$INSTALLER_ISO"
|
||||
# 7z returns exit code 2 for warnings (symlinks in ISO) — check for key files instead
|
||||
7z x -y "$BASE_ISO" >/dev/null 2>&1 || 7za x -y "$BASE_ISO" >/dev/null 2>&1 || bsdtar -xf "$BASE_ISO" 2>/dev/null || true
|
||||
if [ ! -d "$INSTALLER_ISO/live" ] || [ ! -f "$INSTALLER_ISO/live/vmlinuz" ]; then
|
||||
echo " ❌ Failed to extract ISO. Install p7zip-full: sudo apt install p7zip-full"
|
||||
INSTALLER_SQUASHFS="$WORK_DIR/installer-squashfs"
|
||||
rm -rf "$INSTALLER_ISO" "$INSTALLER_SQUASHFS"
|
||||
mkdir -p "$INSTALLER_ISO/live" "$INSTALLER_ISO/archipelago"
|
||||
mkdir -p "$INSTALLER_ISO/boot/grub" "$INSTALLER_ISO/isolinux"
|
||||
mkdir -p "$INSTALLER_ISO/EFI/BOOT"
|
||||
|
||||
# Build the installer filesystem inside a container
|
||||
# This creates: vmlinuz, initrd.img, filesystem.squashfs
|
||||
echo " Building installer rootfs with debootstrap (this takes a few minutes)..."
|
||||
$CONTAINER_CMD run --rm --privileged --platform $CONTAINER_PLATFORM \
|
||||
-v "$WORK_DIR:/output" \
|
||||
-e DEB_ARCH="$DEB_ARCH" \
|
||||
-e LIB_DIR="$LIB_DIR" \
|
||||
debian:bookworm bash -c '
|
||||
set -e
|
||||
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq debootstrap squashfs-tools initramfs-tools dosfstools mtools \
|
||||
grub-efi-amd64-bin grub-pc-bin grub-common isolinux syslinux-common
|
||||
|
||||
echo " [container] Running debootstrap --variant=minbase..."
|
||||
debootstrap --variant=minbase --arch=${DEB_ARCH} \
|
||||
--include=systemd,systemd-sysv,udev,dbus,bash,coreutils,mount,util-linux,\
|
||||
kmod,procps,iproute2,ca-certificates,gdisk,\
|
||||
cryptsetup,cryptsetup-initramfs,parted,dosfstools,e2fsprogs,\
|
||||
linux-image-${DEB_ARCH},grub-efi-${DEB_ARCH},grub-pc-bin,\
|
||||
pciutils,usbutils,less,nano \
|
||||
bookworm /installer http://deb.debian.org/debian
|
||||
|
||||
echo " [container] Configuring installer environment..."
|
||||
|
||||
# Set hostname
|
||||
echo "archipelago-installer" > /installer/etc/hostname
|
||||
|
||||
# Set root password
|
||||
echo "root:archipelago" | chroot /installer chpasswd
|
||||
|
||||
# Auto-login on tty1
|
||||
mkdir -p /installer/etc/systemd/system/getty@tty1.service.d
|
||||
cat > /installer/etc/systemd/system/getty@tty1.service.d/autologin.conf <<GETTY
|
||||
[Service]
|
||||
ExecStart=
|
||||
ExecStart=-/sbin/agetty --autologin root --noclear %I \$TERM
|
||||
GETTY
|
||||
|
||||
# Create the installer auto-start systemd service
|
||||
cat > /installer/etc/systemd/system/archipelago-installer.service <<SVCFILE
|
||||
[Unit]
|
||||
Description=Archipelago Auto-Installer
|
||||
After=multi-user.target systemd-logind.service
|
||||
Wants=multi-user.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/local/bin/archipelago-start-installer
|
||||
StandardInput=tty
|
||||
StandardOutput=tty
|
||||
StandardError=tty
|
||||
TTYPath=/dev/tty1
|
||||
TTYReset=yes
|
||||
TTYVHangup=yes
|
||||
RemainAfterExit=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
SVCFILE
|
||||
chroot /installer systemctl enable archipelago-installer.service
|
||||
|
||||
# Create the installer start wrapper
|
||||
cat > /installer/usr/local/bin/archipelago-start-installer <<WRAPPER
|
||||
#!/bin/bash
|
||||
sleep 2
|
||||
clear
|
||||
echo ""
|
||||
echo " ARCHIPELAGO BITCOIN NODE OS"
|
||||
echo " Automatic Installer"
|
||||
echo ""
|
||||
|
||||
BOOT_MEDIA=""
|
||||
for dev in /run/archiso /cdrom /media/cdrom /mnt/iso; do
|
||||
if [ -f "\$dev/archipelago/auto-install.sh" ]; then
|
||||
BOOT_MEDIA="\$dev"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "\$BOOT_MEDIA" ]; then
|
||||
echo " Found installer at: \$BOOT_MEDIA"
|
||||
echo ""
|
||||
echo " Press Enter to start installation, or Ctrl+C for shell..."
|
||||
read
|
||||
exec bash "\$BOOT_MEDIA/archipelago/auto-install.sh"
|
||||
else
|
||||
echo " Installer not found on boot media."
|
||||
echo " Checked: /run/archiso, /cdrom, /media/cdrom, /mnt/iso"
|
||||
echo ""
|
||||
echo " Dropping to shell for manual recovery..."
|
||||
exec /bin/bash
|
||||
fi
|
||||
WRAPPER
|
||||
chmod +x /installer/usr/local/bin/archipelago-start-installer
|
||||
|
||||
# Custom initramfs hook: mount ISO boot media at /run/archiso
|
||||
mkdir -p /installer/etc/initramfs-tools/hooks
|
||||
cat > /installer/etc/initramfs-tools/hooks/archipelago <<HOOK
|
||||
#!/bin/sh
|
||||
set -e
|
||||
PREREQ=""
|
||||
prereqs() { echo "\$PREREQ"; }
|
||||
case "\$1" in prereqs) prereqs; exit 0;; esac
|
||||
. /usr/share/initramfs-tools/hook-functions
|
||||
# Ensure mount helpers and filesystem tools are in initramfs
|
||||
copy_exec /bin/mount
|
||||
copy_exec /bin/umount
|
||||
copy_exec /bin/findfs 2>/dev/null || true
|
||||
copy_exec /sbin/blkid
|
||||
manual_add_modules iso9660 vfat squashfs overlay
|
||||
HOOK
|
||||
chmod +x /installer/etc/initramfs-tools/hooks/archipelago
|
||||
|
||||
mkdir -p /installer/etc/initramfs-tools/scripts/local-bottom
|
||||
cat > /installer/etc/initramfs-tools/scripts/local-bottom/archipelago-mount <<INITSCRIPT
|
||||
#!/bin/sh
|
||||
PREREQ=""
|
||||
prereqs() { echo "\$PREREQ"; }
|
||||
case "\$1" in prereqs) prereqs; exit 0;; esac
|
||||
|
||||
. /scripts/functions
|
||||
|
||||
# Try to find and mount the Archipelago boot media
|
||||
mkdir -p /run/archiso
|
||||
log_begin_msg "Searching for Archipelago boot media..."
|
||||
|
||||
# Try CD-ROM first, then USB partitions
|
||||
for dev in /dev/sr0 /dev/sd??* /dev/nvme*p*; do
|
||||
[ -b "\$dev" ] 2>/dev/null || continue
|
||||
mount -o ro "\$dev" /run/archiso 2>/dev/null || continue
|
||||
if [ -d /run/archiso/archipelago ]; then
|
||||
log_end_msg 0
|
||||
echo "Found Archipelago media on \$dev"
|
||||
exit 0
|
||||
fi
|
||||
umount /run/archiso 2>/dev/null || true
|
||||
done
|
||||
|
||||
log_end_msg 1
|
||||
echo "Archipelago boot media not found (will retry from userspace)"
|
||||
INITSCRIPT
|
||||
chmod +x /installer/etc/initramfs-tools/scripts/local-bottom/archipelago-mount
|
||||
|
||||
# Strip docs and man pages from installer
|
||||
rm -rf /installer/usr/share/man/* /installer/usr/share/doc/*
|
||||
rm -rf /installer/var/lib/apt/lists/* /installer/var/cache/apt/*
|
||||
|
||||
# Extract kernel
|
||||
KVER=$(ls /installer/lib/modules/ | sort -V | tail -1)
|
||||
echo " [container] Kernel version: $KVER"
|
||||
cp /installer/boot/vmlinuz-$KVER /output/vmlinuz
|
||||
|
||||
# Build initramfs with our custom hooks
|
||||
chroot /installer update-initramfs -c -k $KVER
|
||||
cp /installer/boot/initrd.img-$KVER /output/initrd.img
|
||||
|
||||
# Create squashfs
|
||||
echo " [container] Creating installer squashfs..."
|
||||
mksquashfs /installer /output/filesystem.squashfs -comp xz -Xbcj x86 -noappend -quiet
|
||||
|
||||
# Build GRUB EFI image
|
||||
echo " [container] Building GRUB EFI image..."
|
||||
grub-mkimage -O x86_64-efi -o /output/BOOTX64.EFI -p /boot/grub \
|
||||
part_gpt part_msdos fat iso9660 udf normal boot linux search \
|
||||
search_fs_uuid search_fs_file search_label configfile echo cat \
|
||||
ls test true loopback gfxterm gfxmenu font png
|
||||
|
||||
# Create EFI FAT image (4MB)
|
||||
dd if=/dev/zero of=/output/efi.img bs=1M count=4 2>/dev/null
|
||||
mkfs.vfat /output/efi.img >/dev/null
|
||||
mmd -i /output/efi.img ::/EFI ::/EFI/BOOT
|
||||
mcopy -i /output/efi.img /output/BOOTX64.EFI ::/EFI/BOOT/BOOTX64.EFI
|
||||
|
||||
# Copy ISOLINUX files for legacy BIOS boot
|
||||
cp /usr/lib/ISOLINUX/isolinux.bin /output/isolinux.bin
|
||||
cp /usr/lib/syslinux/modules/bios/ldlinux.c32 /output/ldlinux.c32
|
||||
cp /usr/lib/syslinux/modules/bios/menu.c32 /output/menu.c32 2>/dev/null || true
|
||||
cp /usr/lib/syslinux/modules/bios/libutil.c32 /output/libutil.c32 2>/dev/null || true
|
||||
cp /usr/lib/ISOLINUX/isohdpfx.bin /output/isohdpfx.bin
|
||||
|
||||
# Generate GRUB fonts for theme
|
||||
echo " [container] Generating GRUB fonts..."
|
||||
apt-get install -y -qq fonts-dejavu-core grub-common >/dev/null 2>&1
|
||||
mkdir -p /output/grub-fonts
|
||||
grub-mkfont -s 12 -o /output/grub-fonts/dejavu_12.pf2 /usr/share/fonts/truetype/dejavu/DejaVuSans.ttf
|
||||
grub-mkfont -s 14 -o /output/grub-fonts/dejavu_14.pf2 /usr/share/fonts/truetype/dejavu/DejaVuSans.ttf
|
||||
grub-mkfont -s 16 -o /output/grub-fonts/dejavu_16.pf2 /usr/share/fonts/truetype/dejavu/DejaVuSans.ttf
|
||||
grub-mkfont -s 24 -o /output/grub-fonts/dejavu_24.pf2 /usr/share/fonts/truetype/dejavu/DejaVuSansMono-Bold.ttf
|
||||
|
||||
echo " [container] Done!"
|
||||
'
|
||||
|
||||
# Verify artifacts
|
||||
for artifact in vmlinuz initrd.img filesystem.squashfs BOOTX64.EFI efi.img isolinux.bin isohdpfx.bin; do
|
||||
if [ ! -f "$WORK_DIR/$artifact" ]; then
|
||||
echo " FATAL: Missing build artifact: $artifact"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Place artifacts into ISO directory structure
|
||||
cp "$WORK_DIR/vmlinuz" "$INSTALLER_ISO/live/vmlinuz"
|
||||
cp "$WORK_DIR/initrd.img" "$INSTALLER_ISO/live/initrd.img"
|
||||
cp "$WORK_DIR/filesystem.squashfs" "$INSTALLER_ISO/live/filesystem.squashfs"
|
||||
cp "$WORK_DIR/BOOTX64.EFI" "$INSTALLER_ISO/EFI/BOOT/BOOTX64.EFI"
|
||||
cp "$WORK_DIR/efi.img" "$INSTALLER_ISO/boot/grub/efi.img"
|
||||
cp "$WORK_DIR/isolinux.bin" "$INSTALLER_ISO/isolinux/isolinux.bin"
|
||||
cp "$WORK_DIR/ldlinux.c32" "$INSTALLER_ISO/isolinux/ldlinux.c32"
|
||||
cp "$WORK_DIR/menu.c32" "$INSTALLER_ISO/isolinux/menu.c32" 2>/dev/null || true
|
||||
cp "$WORK_DIR/libutil.c32" "$INSTALLER_ISO/isolinux/libutil.c32" 2>/dev/null || true
|
||||
|
||||
# Install GRUB theme
|
||||
THEME_SRC="$SCRIPT_DIR/branding/grub-theme"
|
||||
THEME_DST="$INSTALLER_ISO/boot/grub/themes/archipelago"
|
||||
mkdir -p "$THEME_DST"
|
||||
if [ -f "$THEME_SRC/theme.txt" ]; then
|
||||
cp "$THEME_SRC/theme.txt" "$THEME_DST/"
|
||||
echo " Installed GRUB theme from branding/grub-theme/"
|
||||
fi
|
||||
# Install generated fonts
|
||||
if [ -d "$WORK_DIR/grub-fonts" ]; then
|
||||
cp "$WORK_DIR/grub-fonts/"*.pf2 "$THEME_DST/"
|
||||
# Also copy unicode font for GRUB to load
|
||||
cp "$WORK_DIR/grub-fonts/dejavu_16.pf2" "$INSTALLER_ISO/boot/grub/font.pf2"
|
||||
fi
|
||||
|
||||
echo " Installer squashfs: $(du -h "$INSTALLER_ISO/live/filesystem.squashfs" | cut -f1)"
|
||||
echo " Kernel: $(du -h "$INSTALLER_ISO/live/vmlinuz" | cut -f1)"
|
||||
echo " Initrd: $(du -h "$INSTALLER_ISO/live/initrd.img" | cut -f1)"
|
||||
echo " Step 2 complete (custom minimal base, no Debian Live)"
|
||||
|
||||
# =============================================================================
|
||||
# STEP 3: Add Archipelago components
|
||||
@ -1152,7 +1324,7 @@ echo ""
|
||||
|
||||
# Find boot media
|
||||
BOOT_MEDIA=""
|
||||
for dev in /run/live/medium /lib/live/mount/medium /cdrom; do
|
||||
for dev in /run/archiso /cdrom /media/cdrom /run/live/medium /lib/live/mount/medium /mnt/iso; do
|
||||
if [ -d "$dev/archipelago" ]; then
|
||||
BOOT_MEDIA="$dev"
|
||||
break
|
||||
@ -1694,8 +1866,9 @@ while true; do
|
||||
--disable-save-password-bubble \
|
||||
--disable-suggestions-service \
|
||||
--password-store=basic \
|
||||
--disable-features=TranslateUI,PasswordManagerOnboarding \
|
||||
--disable-features=TranslateUI,PasswordManagerOnboarding,AutofillServerCommunication,PasswordManagerEnabled \
|
||||
--disable-component-update \
|
||||
--credentials_enable_service=false \
|
||||
--user-data-dir=/home/archipelago/.config/chromium-kiosk
|
||||
sleep 3
|
||||
done
|
||||
@ -1869,10 +2042,8 @@ elif [ -n "${GRUB_BIOS_TARGET}" ]; then
|
||||
echo " Skipping Legacy BIOS bootloader (machine supports UEFI)"
|
||||
fi
|
||||
|
||||
# Remove any live-boot artifacts that could cause squashfs errors on boot
|
||||
# These can sneak in from Docker base image or package dependencies
|
||||
echo " Cleaning live-boot artifacts..."
|
||||
chroot /mnt/target apt-get remove -y --purge live-boot live-boot-initramfs-tools live-config 2>/dev/null || true
|
||||
# Clean any stale live-boot artifacts (should not exist in the custom rootfs,
|
||||
# but clean up defensively in case Docker base image pulled them in)
|
||||
rm -f /mnt/target/etc/initramfs-tools/conf.d/live-boot* 2>/dev/null || true
|
||||
rm -f /mnt/target/usr/share/initramfs-tools/scripts/live* 2>/dev/null || true
|
||||
rm -f /mnt/target/usr/share/initramfs-tools/hooks/live* 2>/dev/null || true
|
||||
@ -1880,6 +2051,14 @@ rm -f /mnt/target/usr/share/initramfs-tools/hooks/live* 2>/dev/null || true
|
||||
# Suppress os-prober warning in GRUB
|
||||
echo "GRUB_DISABLE_OS_PROBER=true" >> /mnt/target/etc/default/grub
|
||||
|
||||
# Install Archipelago GRUB theme on target system
|
||||
if [ -d "$BOOT_MEDIA/boot/grub/themes/archipelago" ]; then
|
||||
mkdir -p /mnt/target/boot/grub/themes/archipelago
|
||||
cp "$BOOT_MEDIA/boot/grub/themes/archipelago/"* /mnt/target/boot/grub/themes/archipelago/
|
||||
echo 'GRUB_THEME="/boot/grub/themes/archipelago/theme.txt"' >> /mnt/target/etc/default/grub
|
||||
echo " Installed Archipelago GRUB theme on target"
|
||||
fi
|
||||
|
||||
# Regenerate initramfs — the one from Docker export is corrupt/incomplete
|
||||
# (Docker builds have limited /proc, /sys, /dev so initramfs generation fails silently)
|
||||
echo " Regenerating initramfs..."
|
||||
@ -1888,8 +2067,12 @@ chroot /mnt/target update-initramfs -u -k all
|
||||
chroot /mnt/target update-grub
|
||||
|
||||
# Install udev rule for mesh radio stable naming (/dev/mesh-radio)
|
||||
if [ -f /cdrom/99-mesh-radio.rules ]; then
|
||||
cp /cdrom/99-mesh-radio.rules /mnt/target/etc/udev/rules.d/99-mesh-radio.rules
|
||||
MESH_RULES=""
|
||||
for p in "$BOOT_MEDIA/99-mesh-radio.rules" /cdrom/99-mesh-radio.rules "$BOOT_MEDIA/archipelago/configs/99-mesh-radio.rules"; do
|
||||
[ -f "$p" ] && MESH_RULES="$p" && break
|
||||
done
|
||||
if [ -n "$MESH_RULES" ]; then
|
||||
cp "$MESH_RULES" /mnt/target/etc/udev/rules.d/99-mesh-radio.rules
|
||||
echo " Installed mesh radio udev rule"
|
||||
fi
|
||||
|
||||
@ -2207,12 +2390,13 @@ read -p "Press Enter to reboot (make sure USB is removed)..."
|
||||
exec 2>/dev/null
|
||||
|
||||
# Try to eject the USB boot media to prevent booting back into installer
|
||||
BOOT_DEV=$(findmnt -n -o SOURCE /run/live/medium 2>/dev/null || findmnt -n -o SOURCE /lib/live/mount/medium 2>/dev/null || echo "")
|
||||
BOOT_DEV=$(findmnt -n -o SOURCE /run/archiso 2>/dev/null || findmnt -n -o SOURCE /cdrom 2>/dev/null || findmnt -n -o SOURCE /run/live/medium 2>/dev/null || echo "")
|
||||
if [ -n "$BOOT_DEV" ]; then
|
||||
BOOT_DISK=$(lsblk -no PKNAME "$BOOT_DEV" 2>/dev/null | head -1)
|
||||
if [ -n "$BOOT_DISK" ]; then
|
||||
umount -l /run/archiso 2>/dev/null || true
|
||||
umount -l /cdrom 2>/dev/null || true
|
||||
umount -l /run/live/medium 2>/dev/null || true
|
||||
umount -l /lib/live/mount/medium 2>/dev/null || true
|
||||
eject "/dev/$BOOT_DISK" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
@ -2230,227 +2414,100 @@ fi
|
||||
chmod +x "$ARCH_DIR/auto-install.sh"
|
||||
|
||||
# =============================================================================
|
||||
# STEP 5: Configure auto-start installer on boot
|
||||
# STEP 5: Configure boot loader and ISO structure
|
||||
# =============================================================================
|
||||
echo ""
|
||||
echo "📦 Step 5: Configuring auto-start..."
|
||||
echo "Step 5: Configuring boot loaders..."
|
||||
|
||||
# Create a squashfs overlay module that Debian Live will automatically load
|
||||
# This is the proper way to add files to the live filesystem
|
||||
OVERLAY_DIR="$WORK_DIR/overlay-root"
|
||||
rm -rf "$OVERLAY_DIR"
|
||||
mkdir -p "$OVERLAY_DIR/etc/profile.d"
|
||||
mkdir -p "$OVERLAY_DIR/etc/skel"
|
||||
mkdir -p "$OVERLAY_DIR/usr/local/bin"
|
||||
mkdir -p "$OVERLAY_DIR/usr/sbin"
|
||||
mkdir -p "$OVERLAY_DIR/sbin"
|
||||
# The installer squashfs (from Step 2) already contains:
|
||||
# - systemd service for auto-starting the installer
|
||||
# - auto-login on tty1
|
||||
# - custom initramfs hook for mounting boot media at /run/archiso
|
||||
# - all partitioning tools (parted, mkfs.*, cryptsetup)
|
||||
#
|
||||
# Step 5 just needs to create the GRUB and ISOLINUX boot configs.
|
||||
|
||||
# Download and extract required tools AND their libraries for offline use
|
||||
echo " Downloading partitioning tools for offline use..."
|
||||
TOOLS_DIR="$WORK_DIR/tools-extract"
|
||||
rm -rf "$TOOLS_DIR"
|
||||
mkdir -p "$TOOLS_DIR"
|
||||
# Create GRUB configuration
|
||||
echo " Writing GRUB config..."
|
||||
cat > "$INSTALLER_ISO/boot/grub/grub.cfg" <<'GRUBCFG'
|
||||
set timeout=5
|
||||
set default=0
|
||||
|
||||
$CONTAINER_CMD run --rm --platform $CONTAINER_PLATFORM \
|
||||
-v "$TOOLS_DIR:/output" \
|
||||
debian:bookworm \
|
||||
bash -c '
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq parted dosfstools e2fsprogs
|
||||
|
||||
# Copy binaries
|
||||
cp /usr/sbin/parted /output/
|
||||
cp /usr/sbin/mkfs.vfat /output/ 2>/dev/null || cp /sbin/mkfs.vfat /output/ 2>/dev/null || true
|
||||
cp /usr/sbin/mkfs.ext4 /output/ 2>/dev/null || cp /sbin/mkfs.ext4 /output/ 2>/dev/null || true
|
||||
cp /usr/sbin/mke2fs /output/ 2>/dev/null || cp /sbin/mke2fs /output/ 2>/dev/null || true
|
||||
cp /sbin/mkfs.fat /output/ 2>/dev/null || true
|
||||
|
||||
# Copy required shared libraries for parted
|
||||
mkdir -p /output/lib
|
||||
cp /lib/${LIB_DIR}/libparted.so* /output/lib/ 2>/dev/null || true
|
||||
cp /usr/lib/${LIB_DIR}/libparted.so* /output/lib/ 2>/dev/null || true
|
||||
cp /lib/${LIB_DIR}/libreadline.so* /output/lib/ 2>/dev/null || true
|
||||
cp /usr/lib/${LIB_DIR}/libreadline.so* /output/lib/ 2>/dev/null || true
|
||||
cp /lib/${LIB_DIR}/libdevmapper.so* /output/lib/ 2>/dev/null || true
|
||||
cp /usr/lib/${LIB_DIR}/libdevmapper.so* /output/lib/ 2>/dev/null || true
|
||||
|
||||
# List what parted actually needs
|
||||
ldd /usr/sbin/parted 2>/dev/null | grep "=>" | awk "{print \$3}" | while read lib; do
|
||||
[ -f "$lib" ] && cp "$lib" /output/lib/ 2>/dev/null || true
|
||||
done
|
||||
|
||||
echo "Libraries bundled:"
|
||||
ls -la /output/lib/
|
||||
'
|
||||
|
||||
# Copy tools to overlay
|
||||
cp "$TOOLS_DIR/parted" "$OVERLAY_DIR/usr/sbin/" 2>/dev/null || true
|
||||
cp "$TOOLS_DIR/mkfs.vfat" "$OVERLAY_DIR/usr/sbin/" 2>/dev/null || true
|
||||
cp "$TOOLS_DIR/mkfs.fat" "$OVERLAY_DIR/sbin/" 2>/dev/null || true
|
||||
cp "$TOOLS_DIR/mkfs.ext4" "$OVERLAY_DIR/usr/sbin/" 2>/dev/null || true
|
||||
cp "$TOOLS_DIR/mke2fs" "$OVERLAY_DIR/usr/sbin/" 2>/dev/null || true
|
||||
|
||||
# Copy shared libraries
|
||||
mkdir -p "$OVERLAY_DIR/usr/lib/${LIB_DIR}"
|
||||
cp "$TOOLS_DIR/lib/"*.so* "$OVERLAY_DIR/usr/lib/${LIB_DIR}/" 2>/dev/null || true
|
||||
|
||||
chmod +x "$OVERLAY_DIR/usr/sbin/"* 2>/dev/null || true
|
||||
chmod +x "$OVERLAY_DIR/sbin/"* 2>/dev/null || true
|
||||
echo " ✅ Partitioning tools and libraries bundled"
|
||||
|
||||
# Create the auto-start profile script
|
||||
cat > "$OVERLAY_DIR/etc/profile.d/z99-archipelago-installer.sh" <<'AUTOSTART'
|
||||
#!/bin/bash
|
||||
# Auto-start Archipelago installer on login
|
||||
|
||||
# Only run once
|
||||
if [ -n "$INSTALLER_STARTED" ]; then
|
||||
return 0 2>/dev/null || exit 0
|
||||
# Load font for graphical menu
|
||||
if loadfont /boot/grub/font.pf2; then
|
||||
set gfxmode=auto
|
||||
insmod gfxterm
|
||||
insmod png
|
||||
terminal_output gfxterm
|
||||
fi
|
||||
export INSTALLER_STARTED=1
|
||||
|
||||
# Give system a moment to settle
|
||||
sleep 1
|
||||
|
||||
clear
|
||||
echo ""
|
||||
echo " ╔═══════════════════════════════════════════════════════════════════╗"
|
||||
echo " ║ ║"
|
||||
echo " ║ 🏝️ ARCHIPELAGO BITCOIN NODE OS - INSTALLER ║"
|
||||
echo " ║ ║"
|
||||
echo " ╚═══════════════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
|
||||
# Find boot media
|
||||
BOOT_MEDIA=""
|
||||
for dev in /run/live/medium /lib/live/mount/medium /cdrom /media/cdrom; do
|
||||
if [ -f "$dev/archipelago/auto-install.sh" ]; then
|
||||
BOOT_MEDIA="$dev"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "$BOOT_MEDIA" ]; then
|
||||
echo " Found installer at: $BOOT_MEDIA"
|
||||
echo ""
|
||||
echo " Press Enter to start installation, or Ctrl+C for shell..."
|
||||
read
|
||||
sudo bash "$BOOT_MEDIA/archipelago/auto-install.sh"
|
||||
# Archipelago GRUB theme
|
||||
if [ -f /boot/grub/themes/archipelago/theme.txt ]; then
|
||||
# Load theme fonts
|
||||
loadfont /boot/grub/themes/archipelago/dejavu_12.pf2
|
||||
loadfont /boot/grub/themes/archipelago/dejavu_14.pf2
|
||||
loadfont /boot/grub/themes/archipelago/dejavu_16.pf2
|
||||
loadfont /boot/grub/themes/archipelago/dejavu_24.pf2
|
||||
set theme=/boot/grub/themes/archipelago/theme.txt
|
||||
else
|
||||
echo " ⚠️ Installer not found on boot media."
|
||||
echo ""
|
||||
echo " Checked: /run/live/medium, /lib/live/mount/medium, /cdrom"
|
||||
echo ""
|
||||
echo " You can try manually:"
|
||||
echo " sudo bash /path/to/archipelago/auto-install.sh"
|
||||
echo ""
|
||||
fi
|
||||
AUTOSTART
|
||||
chmod +x "$OVERLAY_DIR/etc/profile.d/z99-archipelago-installer.sh"
|
||||
|
||||
# Also create .bashrc that sources the profile script (belt and suspenders)
|
||||
cat > "$OVERLAY_DIR/etc/skel/.bashrc" <<'BASHRC'
|
||||
# ~/.bashrc: executed by bash(1) for non-login shells.
|
||||
|
||||
# If not running interactively, don't do anything
|
||||
case $- in
|
||||
*i*) ;;
|
||||
*) return;;
|
||||
esac
|
||||
|
||||
# Source profile.d scripts
|
||||
if [ -d /etc/profile.d ]; then
|
||||
for i in /etc/profile.d/*.sh; do
|
||||
if [ -r "$i" ]; then
|
||||
. "$i"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
BASHRC
|
||||
|
||||
# Create a wrapper script that can be called directly
|
||||
cat > "$OVERLAY_DIR/usr/local/bin/archipelago-install" <<'WRAPPER'
|
||||
#!/bin/bash
|
||||
# Archipelago installer wrapper
|
||||
|
||||
BOOT_MEDIA=""
|
||||
for dev in /run/live/medium /lib/live/mount/medium /cdrom /media/cdrom; do
|
||||
if [ -f "$dev/archipelago/auto-install.sh" ]; then
|
||||
BOOT_MEDIA="$dev"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "$BOOT_MEDIA" ]; then
|
||||
exec sudo bash "$BOOT_MEDIA/archipelago/auto-install.sh"
|
||||
else
|
||||
echo "Installer not found. Searched:"
|
||||
echo " /run/live/medium, /lib/live/mount/medium, /cdrom, /media/cdrom"
|
||||
exit 1
|
||||
fi
|
||||
WRAPPER
|
||||
chmod +x "$OVERLAY_DIR/usr/local/bin/archipelago-install"
|
||||
|
||||
# Create the squashfs module
|
||||
# Debian Live automatically loads all .squashfs files from live/ directory
|
||||
echo " Creating overlay squashfs module..."
|
||||
LIVE_DIR="$INSTALLER_ISO/live"
|
||||
mkdir -p "$LIVE_DIR"
|
||||
|
||||
# Check if mksquashfs is available (may need to use Docker on macOS)
|
||||
if command -v mksquashfs >/dev/null 2>&1; then
|
||||
mksquashfs "$OVERLAY_DIR" "$LIVE_DIR/99-archipelago.squashfs" -comp xz -noappend
|
||||
else
|
||||
# Use $CONTAINER_CMD to create squashfs on macOS
|
||||
echo " Using $CONTAINER_CMD to create squashfs..."
|
||||
$CONTAINER_CMD run --rm --platform $CONTAINER_PLATFORM \
|
||||
-v "$OVERLAY_DIR:/overlay:ro" \
|
||||
-v "$LIVE_DIR:/output" \
|
||||
debian:bookworm \
|
||||
bash -c "apt-get update && apt-get install -y squashfs-tools && mksquashfs /overlay /output/99-archipelago.squashfs -comp xz -noappend"
|
||||
set menu_color_normal=light-gray/black
|
||||
set menu_color_highlight=white/dark-gray
|
||||
fi
|
||||
|
||||
echo " ✅ Created overlay module: 99-archipelago.squashfs"
|
||||
menuentry "Install Archipelago" --hotkey=i {
|
||||
linux /live/vmlinuz quiet
|
||||
initrd /live/initrd.img
|
||||
}
|
||||
|
||||
# Modify GRUB config - update branding and ensure components are loaded
|
||||
if [ -f "$INSTALLER_ISO/boot/grub/grub.cfg" ]; then
|
||||
echo " Configuring GRUB..."
|
||||
sed -i.bak \
|
||||
-e 's/Debian GNU\/Linux/Archipelago Installer/g' \
|
||||
-e 's/Live system/Install Archipelago/g' \
|
||||
"$INSTALLER_ISO/boot/grub/grub.cfg"
|
||||
menuentry "Install Archipelago (verbose)" --hotkey=v {
|
||||
linux /live/vmlinuz
|
||||
initrd /live/initrd.img
|
||||
}
|
||||
|
||||
# Ensure 'components' parameter is present (loads additional squashfs modules)
|
||||
# Also add 'username=user' to ensure consistent username
|
||||
if ! grep -q "components" "$INSTALLER_ISO/boot/grub/grub.cfg"; then
|
||||
sed -i 's/boot=live/boot=live components/' "$INSTALLER_ISO/boot/grub/grub.cfg"
|
||||
fi
|
||||
fi
|
||||
menuentry "Boot from local disk" --hotkey=b {
|
||||
set root=(hd0)
|
||||
chainloader +1
|
||||
}
|
||||
GRUBCFG
|
||||
|
||||
if [ -f "$INSTALLER_ISO/isolinux/live.cfg" ]; then
|
||||
echo " Configuring ISOLINUX..."
|
||||
sed -i.bak \
|
||||
-e 's/Debian GNU\/Linux/Archipelago Installer/g' \
|
||||
-e 's/Live system/Install Archipelago/g' \
|
||||
"$INSTALLER_ISO/isolinux/live.cfg"
|
||||
# Create ISOLINUX configuration (legacy BIOS boot)
|
||||
echo " Writing ISOLINUX config..."
|
||||
cat > "$INSTALLER_ISO/isolinux/isolinux.cfg" <<'ISOCFG'
|
||||
UI menu.c32
|
||||
PROMPT 0
|
||||
TIMEOUT 50
|
||||
|
||||
# Add components parameter
|
||||
if ! grep -q "components" "$INSTALLER_ISO/isolinux/live.cfg"; then
|
||||
sed -i 's/boot=live/boot=live components/' "$INSTALLER_ISO/isolinux/live.cfg"
|
||||
fi
|
||||
fi
|
||||
MENU TITLE ARCHIPELAGO INSTALLER
|
||||
MENU COLOR border 30;44 #40ffffff #00000000 std
|
||||
MENU COLOR title 1;36;44 #ff00b7ff #00000000 std
|
||||
MENU COLOR sel 7;37;40 #ffffffff #ff333333 std
|
||||
MENU COLOR unsel 37;44 #ffaaaaaa #00000000 std
|
||||
|
||||
if [ -f "$INSTALLER_ISO/isolinux/menu.cfg" ]; then
|
||||
sed -i.bak \
|
||||
-e 's/Debian GNU\/Linux/Archipelago Installer/g' \
|
||||
"$INSTALLER_ISO/isolinux/menu.cfg"
|
||||
fi
|
||||
DEFAULT install
|
||||
|
||||
LABEL install
|
||||
MENU LABEL Install Archipelago
|
||||
KERNEL /live/vmlinuz
|
||||
APPEND initrd=/live/initrd.img quiet
|
||||
MENU DEFAULT
|
||||
|
||||
LABEL install-verbose
|
||||
MENU LABEL Install Archipelago (verbose)
|
||||
KERNEL /live/vmlinuz
|
||||
APPEND initrd=/live/initrd.img
|
||||
|
||||
LABEL local
|
||||
MENU LABEL Boot from local disk
|
||||
LOCALBOOT 0x80
|
||||
ISOCFG
|
||||
|
||||
echo " Step 5 complete (GRUB + ISOLINUX configured)"
|
||||
|
||||
# =============================================================================
|
||||
# STEP 6: Create final ISO
|
||||
# =============================================================================
|
||||
echo ""
|
||||
echo "📦 Step 6: Creating bootable ISO..."
|
||||
echo "Step 6: Creating bootable ISO..."
|
||||
|
||||
if [ "$UNBUNDLED" = "1" ]; then
|
||||
OUTPUT_ISO="$OUTPUT_DIR/archipelago-installer-unbundled-${ARCH}.iso"
|
||||
@ -2458,60 +2515,27 @@ else
|
||||
OUTPUT_ISO="$OUTPUT_DIR/archipelago-installer-${ARCH}.iso"
|
||||
fi
|
||||
|
||||
# Extract MBR from original Debian Live ISO (most reliable for hybrid boot)
|
||||
# This preserves the exact MBR that makes the ISO work as a USB drive in Balena Etcher
|
||||
echo " Extracting hybrid MBR from original Debian Live ISO..."
|
||||
# Use ISOLINUX isohdpfx.bin for hybrid USB boot (built in Step 2)
|
||||
ISOHDPFX="$WORK_DIR/isohdpfx.bin"
|
||||
dd if="$BASE_ISO" bs=1 count=432 of="$ISOHDPFX" 2>/dev/null
|
||||
|
||||
# Verify we got a valid MBR (should be 432 bytes)
|
||||
ISOHDPFX_SIZE=$(stat -c%s "$ISOHDPFX" 2>/dev/null || stat -f%z "$ISOHDPFX" 2>/dev/null || echo 0)
|
||||
if [ "$ISOHDPFX_SIZE" -ne 432 ]; then
|
||||
echo " ⚠️ MBR extraction unexpected size ($ISOHDPFX_SIZE), trying syslinux paths..."
|
||||
if [ ! -f "$ISOHDPFX" ]; then
|
||||
# Fallback to system-installed copy
|
||||
for path in \
|
||||
"/usr/lib/ISOLINUX/isohdpfx.bin" \
|
||||
"/usr/share/syslinux/isohdpfx.bin" \
|
||||
"/usr/local/share/syslinux/isohdpfx.bin"; do
|
||||
if [ -f "$path" ]; then
|
||||
ISOHDPFX="$path"
|
||||
echo " Using $path"
|
||||
echo " Using system isohdpfx.bin: $path"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Find the EFI boot image — 7z may extract it to different locations
|
||||
EFI_IMG=""
|
||||
for efi_path in \
|
||||
"$INSTALLER_ISO/boot/grub/efi.img" \
|
||||
"$INSTALLER_ISO/EFI/boot/efi.img" \
|
||||
"$INSTALLER_ISO/efi.img"; do
|
||||
if [ -f "$efi_path" ]; then
|
||||
EFI_IMG="$efi_path"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# If no standalone efi.img, check for [BOOT] directory from 7z extraction
|
||||
if [ -z "$EFI_IMG" ] && [ -d "$INSTALLER_ISO/[BOOT]" ]; then
|
||||
# 7z extracts El Torito boot images into [BOOT]/ — the EFI image is usually entry 2
|
||||
for entry in "$INSTALLER_ISO/[BOOT]/"*; do
|
||||
# EFI images are typically > 1MB FAT filesystems
|
||||
if [ -f "$entry" ]; then
|
||||
entry_size=$(stat -c%s "$entry" 2>/dev/null || stat -f%z "$entry" 2>/dev/null || echo 0)
|
||||
if [ "$entry_size" -gt 1048576 ]; then
|
||||
mkdir -p "$INSTALLER_ISO/boot/grub"
|
||||
cp "$entry" "$INSTALLER_ISO/boot/grub/efi.img"
|
||||
# EFI boot image was built in Step 2
|
||||
EFI_IMG="$INSTALLER_ISO/boot/grub/efi.img"
|
||||
echo " Recovered EFI image from [BOOT] directory"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ -z "$EFI_IMG" ]; then
|
||||
echo " ⚠️ No EFI boot image found — ISO will only support Legacy BIOS boot"
|
||||
if [ ! -f "$EFI_IMG" ]; then
|
||||
echo " WARNING: No EFI boot image — ISO will only support Legacy BIOS boot"
|
||||
xorriso -as mkisofs -o "$OUTPUT_ISO" \
|
||||
-volid "ARCHIPELAGO" \
|
||||
-iso-level 3 \
|
||||
@ -2523,8 +2547,6 @@ if [ -z "$EFI_IMG" ]; then
|
||||
-partition_offset 16 \
|
||||
"$INSTALLER_ISO"
|
||||
else
|
||||
# Make EFI path relative to INSTALLER_ISO for xorriso
|
||||
EFI_REL="${EFI_IMG#$INSTALLER_ISO/}"
|
||||
xorriso -as mkisofs -o "$OUTPUT_ISO" \
|
||||
-volid "ARCHIPELAGO" \
|
||||
-iso-level 3 \
|
||||
@ -2534,7 +2556,7 @@ else
|
||||
-b isolinux/isolinux.bin \
|
||||
-no-emul-boot -boot-load-size 4 -boot-info-table \
|
||||
-eltorito-alt-boot \
|
||||
-e "$EFI_REL" \
|
||||
-e boot/grub/efi.img \
|
||||
-no-emul-boot \
|
||||
-isohybrid-gpt-basdat \
|
||||
-partition_offset 16 \
|
||||
@ -2543,43 +2565,19 @@ fi
|
||||
|
||||
echo ""
|
||||
if [ "$UNBUNDLED" = "1" ]; then
|
||||
echo "╔════════════════════════════════════════════════════════════════╗"
|
||||
echo "║ ✅ UNBUNDLED AUTO-INSTALLER ISO CREATED! ║"
|
||||
echo "╚════════════════════════════════════════════════════════════════╝"
|
||||
echo "UNBUNDLED AUTO-INSTALLER ISO CREATED"
|
||||
echo ""
|
||||
echo "📀 Output: $OUTPUT_ISO"
|
||||
echo " Output: $OUTPUT_ISO"
|
||||
echo " Size: $(du -h "$OUTPUT_ISO" | cut -f1)"
|
||||
echo ""
|
||||
echo "🔥 Lightweight installer — apps downloaded on-demand!"
|
||||
echo ""
|
||||
echo "Features:"
|
||||
echo " • Pre-built system (no internet needed during install)"
|
||||
echo " • Auto-detects internal disk"
|
||||
echo " • One-button installation"
|
||||
echo " • Boots directly to Archipelago after install"
|
||||
echo " • NO pre-bundled apps (smaller ISO)"
|
||||
echo " • Install any app from the Marketplace (internet required)"
|
||||
echo ""
|
||||
echo " Lightweight installer -- apps downloaded on-demand from Marketplace"
|
||||
else
|
||||
echo "╔════════════════════════════════════════════════════════════════╗"
|
||||
echo "║ ✅ AUTO-INSTALLER ISO CREATED! ║"
|
||||
echo "╚════════════════════════════════════════════════════════════════╝"
|
||||
echo "AUTO-INSTALLER ISO CREATED"
|
||||
echo ""
|
||||
echo "📀 Output: $OUTPUT_ISO"
|
||||
echo " Output: $OUTPUT_ISO"
|
||||
echo " Size: $(du -h "$OUTPUT_ISO" | cut -f1)"
|
||||
echo ""
|
||||
echo "🔥 This is a StartOS-like automatic installer!"
|
||||
echo ""
|
||||
echo "Features:"
|
||||
echo " • Pre-built system (no internet needed during install)"
|
||||
echo " • Auto-detects internal disk"
|
||||
echo " • One-button installation"
|
||||
echo " • Boots directly to Archipelago after install"
|
||||
echo " • Pre-bundled container apps:"
|
||||
echo " - Bitcoin Knots v29"
|
||||
echo " - LND v0.18.4"
|
||||
echo " - Home Assistant"
|
||||
echo ""
|
||||
echo " Full installer with pre-bundled container apps"
|
||||
fi
|
||||
echo "To create USB:"
|
||||
echo " 1. Flash with: sudo dd if=$OUTPUT_ISO of=/dev/rdiskX bs=4m"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user