# Raspberry Pi ARM64 Test Install **Status: Phase 0 — tooling + runbook.** Validates the ARM64 port on commodity hardware (Pi 5) *before* committing to a real Pi image recipe. This is **not** a shippable ARM image: the ARM image is explicitly out of scope for phase 1 (see `kdump-rasdaemon-design.md`), and the porting gap analysis in `apple-silicon-m2-development-research.md` (written for M2/Asahi) still has open items — most notably arch-aware OTA. The Pi is *easier* than that doc's M2 plan in two ways: stock Debian 13 trixie (no Asahi 16K-page concerns) and Xorg/Mesa works, so no Wayland kiosk port is needed for a headless test. Reference material for the eventual image recipe: `image-recipe/raspberrypi/` holds a dissected Start9 embassyOS Pi image (`config.txt`/`cmdline.txt` boot chain, embassyOS partition layout, `init_resize.sh`). Nothing consumes it yet. **Dedicated ARM64 build machine: the M2 Air** (the `apple-silicon-m2-development-research.md` reference machine). In its *build* role it needs no Asahi — macOS + Docker / podman machine run arm64 Linux containers natively, so every build below runs at full speed with no qemu. Asahi only matters for the M2 as a *target* device, which remains a separate milestone in that doc. Keep x86_64 builds on the x86_64 fleet hosts — emulating amd64 on Apple Silicon is the slow direction. ## What changed to enable this | Change | File | | --- | --- | | Optional arch arg (`x86_64` default, `aarch64`); arch-suffixed tags; SHA-256 + GPG fail-closed verification unchanged | `scripts/build-bitcoin-image.sh` | | `ARCH=aarch64` cross build: cargo-zigbuild on host (fast) or emulated `rust:trixie` Docker (slow, zero setup). Backend is rustls-only, so no sysroot libs needed | `image-recipe/scripts/build-backend.sh` | | Dockerfile comments mention the aarch64 tarballs | `apps/bitcoin-core/Dockerfile`, `apps/bitcoin-knots/Dockerfile` | | Frontend | unchanged — Node build, arch-agnostic | Default (no-arg) behavior of both scripts is byte-identical to before. ## Hardware - Raspberry Pi 5 — 4 GB is fine for signet; 8 GB for anything mainnet-ish - 27 W PSU; storage: NVMe HAT recommended for a node, SD works for a smoke test - Ethernet ## Part 1 — Build on the M2 (native ARM64) Requirements on the M2: Docker (backend script) and podman + `podman machine` (bitcoin image script). No binfmt registration — arm64 runs natively. Backend: ```bash ARCH=aarch64 image-recipe/scripts/build-backend.sh # → image-recipe/build/backend/archipelago-aarch64 (native-speed arm64 build) ``` Bitcoin Core image — the app manifest pins `source.archipelago-foundation.org/lfg2025/bitcoin:28.4` (`apps/bitcoin-core/manifest.yml`), so build that version for arm64. On the M2 the smoke test also runs natively, so the full fail-closed pipeline (SHA-256 + GPG + `bitcoind --version`) executes at full fidelity: ```bash scripts/build-bitcoin-image.sh core 28.4 aarch64 # builds, verifies, pushes # or build + verify only, then transfer the image as a tarball: NO_PUSH=1 scripts/build-bitcoin-image.sh core 28.4 aarch64 podman save -o bitcoin-28.4-aarch64.tar \ source.archipelago-foundation.org/lfg2025/bitcoin:28.4-aarch64 ``` If the M2 has registry credentials, just push and let the Pi pull directly (skip the save/load hop). Frontend (arch-agnostic — build on either machine): ```bash image-recipe/scripts/build-frontend.sh # → image-recipe/build/frontend/ (static dist) ``` Transfer to the Pi: `archipelago-aarch64`, `bitcoin-28.4-aarch64.tar`, frontend dist tarball, plus `image-recipe/configs/archipelago.service` and `nginx-archipelago.conf` from the repo. ### Alternative — build on the x86_64 host (ThinkPad) Backend cross-compiles natively with cargo-zigbuild (no emulation): ```bash sudo pacman -S cargo-zigbuild # extra repo; pulls zig ARCH=aarch64 image-recipe/scripts/build-backend.sh ``` The bitcoin image build runs its RUN steps under qemu — register handlers once; the smoke test there is best-effort (SHA-256 + GPG remain the real gate, re-verify natively on the Pi): ```bash podman run --privileged quay.io/podman/qemu-user-static --reset -p yes NO_PUSH=1 scripts/build-bitcoin-image.sh core 28.4 aarch64 ``` ## Part 2 — Pi setup Flash **Raspberry Pi OS Lite (64-bit)** — it's Debian 13 trixie, same base as the fleet images — headless with SSH enabled. For NVMe boot set `BOOT_ORDER` in the bootloader EEPROM (`rpiboot`/`rpi-eeprom-config`) and, if needed, `dtparam=pciex1` in `/boot/firmware/config.txt`. Then: ```bash # rootless podman sudo apt update && sudo apt install -y podman uidmap image-recipe/scripts/install-podman.sh # service user — uid 1000 must match XDG_RUNTIME_DIR=/run/user/1000 in the unit sudo useradd -m -u 1000 -s /bin/bash archipelago sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 archipelago # backend sudo install -m755 archipelago-aarch64 /usr/local/bin/archipelago sudo cp archipelago.service /etc/systemd/system/archipelago.service # The unit's ExecStartPre lines use -/+ prefixes, so missing helpers # (ota-crash-guard.sh etc.) are tolerated; trim them if they aren't. sudo systemctl daemon-reload && sudo systemctl enable --now archipelago # Gaps found by the arm64 systemd-container test (2026-10-11) — the unit and # nginx config need these or they fail to start: sudo groupadd -f debian-tor && sudo groupadd -f fips sudo usermod -aG dialout,debian-tor,fips archipelago sudo mkdir -p /home/archipelago/.local/share/containers /home/archipelago/.config/containers \ /var/lib/containers /etc/containers /opt/archipelago/scripts /var/lib/archipelago sudo chown -R archipelago:archipelago /home/archipelago /var/lib/archipelago # nginx config includes snippets and a TLS cert (self-signed is fine for a test) sudo cp -r image-recipe/configs/snippets /etc/nginx/ sudo mkdir -p /etc/archipelago/ssl && sudo openssl req -x509 -newkey rsa:2048 -nodes -days 30 \ -subj /CN=archy-test -keyout /etc/archipelago/ssl/archipelago.key -out /etc/archipelago/ssl/archipelago.crt sudo cp /etc/archipelago/ssl/archipelago.crt /etc/archipelago/ssl/ca-download.crt # frontend + nginx (serves static, proxies API to 127.0.0.1:5678) sudo mkdir -p /opt/archipelago/web-ui && sudo rsync -a dist/ /opt/archipelago/web-ui/ sudo apt install -y nginx sudo rm -f /etc/nginx/sites-enabled/default sudo cp nginx-archipelago.conf /etc/nginx/conf.d/archipelago.conf sudo systemctl reload nginx # bitcoin image: load, then retag to the pinned manifest ref (see caveat below) sudo -u archipelago podman load -i bitcoin-28.4-aarch64.tar sudo -u archipelago podman tag \ source.archipelago-foundation.org/lfg2025/bitcoin:28.4-aarch64 \ source.archipelago-foundation.org/lfg2025/bitcoin:28.4 ``` **Registry caveat:** manifests pin exact image refs and the orchestrator has no arch field, so retagging the loaded image to the pinned ref satisfies the install without a registry round-trip *only if* the installer doesn't force-pull. If it does, either push the `-aarch64` image under the pinned name to a registry you control, or run bitcoind manually for the test and skip the UI install path. For a quick sanity check independent of the app installer: ```bash sudo -u archipelago podman run --rm \ source.archipelago-foundation.org/lfg2025/bitcoin:28.4 bitcoind --version ``` ## Part 3 — Validation checklist - [ ] `uname -m` → `aarch64`; backend up: `systemctl status archipelago` - [ ] `curl -s http://127.0.0.1/health` (via nginx) responds - [ ] The retagged 28.4 image runs natively (command above) — proves no 4K-page/alignment surprises (Pi is 4K, so this should be a non-issue — it's the Asahi targets that need that audit) - [ ] Dashboard reachable from the LAN at `http:///` - [ ] Bitcoin app installs from the UI and the container starts; for a cheap test run signet or pruned rather than a full mainnet sync - [ ] Memory headroom: bitcoind + backend RSS vs total RAM (Pi 5 4 GB is the floor; note it for the eventual image spec) ## Known ARM gaps — expected failures, not test blockers - **OTA has no architecture field** (`core/archipelago/src/update.rs`) — never OTA a Pi test node; it would try to replace the backend with x86 binaries. - **barkd** downloads a `linux-x86_64` binary in its Dockerfile — exclude it. - **App catalog unaudited for arm64** — treat individual app install failures as expected until audited (M2 doc, "ARM64 application compatibility"). - **`-aarch64` tag suffix is a stopgap** — real fix is arch-aware image selection + manifest lists; see the M2 doc's milestones. - **kdump/rasdaemon** phase 1 is amd64-only by design (`kdump-rasdaemon-design.md`). ## Where this goes next (if the test passes) 1. Arch-aware image selection in the orchestrator (replaces the tag suffix). 2. A real Pi image recipe modeled on the embassyOS reference dump — Pi firmware boot (`config.txt`), no GRUB — replacing `install-to-disk.sh`'s amd64 assumptions. 3. Catalog audit for arm64, starting with the pinned bitcoin stack.