Reproducible ArchLinuxARM builds for ARM boards and emulators, driven entirely by Docker Buildx.
This project builds ArchLinuxARM root filesystems and Raspberry Pi disk images using multi-stage Docker builds, entirely on x86_64 via QEMU user-mode emulation. Three images are produced:
| Image | Description |
|---|---|
| base / minimal | Alpine-bootstrapped ArchLinuxARM aarch64 rootfs, produced with pacman and arch-install-scripts rather than a native chroot. |
| aarch64 | The base image plus kernel, glibc, openssh, and DHCP networking via systemd-networkd. |
| astroarch | A KDE Plasma desktop image built on top of the aarch64 image, pre-loaded with an astrophotography stack (KStars/Ekos, INDI, PHD2, astrometry.net index files) and remote access via VNC/RDP. |
Each build target can export a rootfs tarball, and the astroarch rootfs can be converted into a bootable Raspberry Pi .img.
- Docker with Buildx
binfmt/QEMU support forarm64on the build host (theMakefilesets this up for you, see below)- For image creation:
sfdisk,losetup,mkfs.vfat,mkfs.ext4,blkid(Linux only, requiressudo)
git clone git@github.com:MattBlack85/ArchLinuxARM-docker.git
cd ArchLinuxARM-dockerRegister the arm64 QEMU binfmt handler (also done automatically by targets that need it):
make binfmtBuild the minimal ArchLinuxARM image:
make build-minimalBuild the full ArchLinuxARM image (kernel, SSH, networking):
make build-aarch64Build AstroArch (KDE Plasma + astrophotography stack):
make build-astroarchBuild an AUR package (and any AUR-only dependencies) for aarch64 and copy the resulting package file(s) into the current directory:
make build-aur PKG=<aur-package-name>scripts/build-aur.sh recursively resolves and builds AUR-only dependencies, and PKGBUILDs that don't declare aarch64 are built anyway via makepkg --ignorearch. Dependencies are installed by that script running as root directly (not via sudo) — BuildKit mounts RUN steps nosuid, so a setuid tool like sudo can never regain root once a step has dropped to an unprivileged user; only root-to-non-root (su, to run makepkg itself) works reliably there.
| Target | Description |
|---|---|
binfmt |
Registers QEMU's arm64 binfmt handler on the host. |
build-minimal |
Minimal ArchLinuxARM rootfs (dockerfiles/Dockerfile.base, archarm target). |
build-aarch64 |
Full ArchLinuxARM image with kernel, SSH, and networking. |
build-aarch64-rootfs |
Exports the aarch64 rootfs as archlinuxarm-aarch64-rootfs.tar. |
build-astroarch |
AstroArch desktop image (KDE + INDI stack). |
build-astroarch-rootfs |
Builds the AstroArch rootfs image (astroarch-rootfs:latest). |
build-aur PKG=<name> |
Builds an AUR package (and any AUR-only dependencies) for aarch64 (dockerfiles/Dockerfile.aur) and copies the resulting .pkg.tar.* file(s) into the current directory. |
create-rootfs-container |
Creates a throwaway container from astroarch-rootfs:latest to extract its filesystem. |
copy-rootfs-tar |
Copies astroarch-rootfs.tar out of that container into ./rootfs.tar and removes it. |
prepare-img BOARD=<board> |
Builds the rootfs with the board's kernel flavor, then runs scripts/build_img.sh to produce a bootable archarm-<board>-aarch64.img. <board> must match a file in boards/ (currently rpi, orangepi5b, odroid-n2plus). |
- Bootstraps the ArchLinuxARM
aarch64userland from an Alpine builder stage (no native chroot required). - Installs the ArchLinuxARM keyring and package database directly into the target rootfs.
- Final stage (
archarm) is aFROM scratchimage containing the rootfs plusqemu-aarch64-static, so it runs on x86_64 hosts. exporttarget producesarchlinuxarm-aarch64-rootfs.tar.
- Based on the minimal image (
ghcr.io/devducks/archlinuxarm-basic). - Sets the ArchLinuxARM mirrorlist and initializes pacman's keyring.
- Installs
glibc,linux-aarch64,nano,openssh. - Configures DHCP networking via
systemd-networkdand enablessshd. exporttarget producesarchlinuxarm-aarch64-rootfs.tar.
- Based on the aarch64 image (
ghcr.io/devducks/archlinuxarm). - Adds the AstroMatto package repository.
- Installs KDE Plasma, KStars/Ekos, INDI drivers and third-party drivers, PHD2, TigerVNC, XRDP, and supporting tools.
- Downloads astrometry.net index files into the default user's KStars data directory.
astroarch-rootfstarget builds and exports the rootfs directly (no QEMU boot step is needed to finalize the image).
make prepare-img BOARD=rpi # Raspberry Pi
make prepare-img BOARD=orangepi5b # Orange Pi 5 / 5B (rk3588s)
make prepare-img BOARD=odroid-n2plus # Odroid N2+ (Amlogic S922X)This produces archarm-<board>-aarch64.img: a partitioned disk image with a FAT32 /boot and an ext4 /, built by scripts/build_img.sh. Everything board-specific — kernel flavor, boot strategy, partition offset, how to embed a bootloader ahead of the partition table, and the kernel console — lives in boards/<board>.conf, not in the script or the Makefile:
| Board | Kernel | Boot strategy | Notes |
|---|---|---|---|
rpi |
linux-rpi |
firmware (config.txt/cmdline.txt) |
Nothing lives ahead of partition 1. |
orangepi5b |
generic linux-aarch64 |
extlinux |
Embeds a prebuilt rk3588s U-Boot (from schneid-l/u-boot-rockchip) at sector 64, ahead of the partition table. |
odroid-n2plus |
generic linux-aarch64 |
extlinux |
Embeds ArchLinux ARM's mainline U-Boot for the N2 family via a two-step, MBR-preserving write (Amlogic's install scheme, not a single raw offset). Not yet boot-tested on real hardware. |
To add a new board, drop in a boards/<name>.conf setting KERNEL_FLAVOR, BOOT_STRATEGY (firmware or extlinux), BOOT_START, CONSOLE, and (for extlinux boards that need one) UBOOT_URL. The default bootloader install is a single dd at UBOOT_OFFSET_SECTORS; a board whose SoC needs a different write sequence (like Amlogic's MBR-preserving two-step write) overrides the install_bootloader() shell function in its own .conf instead of touching scripts/build_img.sh.
To customize the image before flashing, boot it under QEMU, make your changes, and shut down cleanly:
./scripts/start_qemu.shThen flash it to an SD card:
sudo dd if=archarm-rpi-aarch64.img of=/dev/sdX bs=4M status=progress
syncInsert the card into the board and boot; SSH will be available once DHCP assigns an address.
| Image | User | Password |
|---|---|---|
| ArchLinuxARM (aarch64) | root |
alarm |
| AstroArch | astronaut |
astro |
SSH is enabled by default on both images. Change these credentials before exposing either image on an untrusted network.
The aarch64 image's /etc/pacman.d/mirrorlist is populated with:
Server = http://dk.mirror.archlinuxarm.org/$arch/$repo
Server = http://de3.mirror.archlinuxarm.org/$arch/$repo
Server = http://eu.mirror.archlinuxarm.org/$arch/$repo
Server = http://fl.us.mirror.archlinuxarm.org/$arch/$repo
Adjust mirrors by editing the relevant Dockerfile.
.github/workflows/buildx.yml builds and pushes the minimal and aarch64 images to GHCR (ghcr.io/<owner>/archlinuxarm-basic and ghcr.io/<owner>/archlinuxarm) on pushes to main, on version tags, weekly on a schedule, and on manual dispatch. Pull requests build without pushing.
.
├── boards/
│ ├── rpi.conf
│ ├── orangepi5b.conf
│ └── odroid-n2plus.conf
├── configs/
│ └── resolv.conf
├── dockerfiles/
│ ├── Dockerfile.base
│ ├── Dockerfile.aarch64
│ └── Dockerfile.astroarch
├── scripts/
│ ├── build_img.sh
│ └── start_qemu.sh
├── Makefile
└── README.md