> [!tip]
> Podman Desktop for Windows/WSL2 can replace Docker Desktop. The Podman [Windows guide](https://podman.io/getting-started/installation#windows) walks through installing and exposing the Podman service to WSL2.
Building Raspberry Pi images on an x86 server or desktop lets you automate builds without a physical Pi nearby. Podman's `--platform` support and `qemu-user-static` binfmt handlers emulate ARM, so you can target the same architecture that runs on Pi 3/4/5 as well as older Pi Zero/1/2 models.
| Raspberry Pi model | Target platform | Notes |
| --- | --- | --- |
| Pi 3B+, 4, 5, Zero 2 W | `linux/arm64` | Modern 64-bit firmware. Use the same containerfile as on the Pi. |
| Pi Zero, Pi 1, Pi 2 | `linux/arm/v7` | 32-bit-only. Requires explicit binfmt registration for `arm/v7`. |
## Requirements
- **x86 Linux host:** install `podman` and `qemu-user-static`. On Debian/Ubuntu also install `binfmt-support`; on Fedora/RHEL use the `systemd-binfmt` service (built in).
- **macOS host:** Podman Desktop already includes `linux/arm64` binfmt handlers in its VM; `linux/arm/v7` support must be added manually inside the VM.
- **WSL2/Windows:** install Podman Desktop for Windows and follow the WSL instructions to expose the Podman instance to WSL2.
## Preparing an X86 Linux Host
### Debian / Ubuntu
1. Install Podman and the QEMU binfmt helpers:
```bash
sudo apt-get update
sudo apt-get install -y podman qemu-user-static binfmt-support
sudo systemctl enable --now systemd-binfmt
```
2. Register the emulators for all targets (including `linux/arm64` and `linux/arm/v7`). Tonistiigi's helper container works well with Podman:
```bash
sudo podman run --rm --privileged docker.io/tonistiigi/binfmt --install all
```
3. Confirm the interpreters are registered:
```bash
ls /proc/sys/fs/binfmt_misc | grep -E "arm"
```
### Fedora / RHEL
`binfmt-support` is a Debian package and does not exist on Fedora. Use `qemu-user-static` with the `systemd-binfmt` service instead:
1. Install `qemu-user-static`:
```bash
sudo dnf install -y qemu-user-static
```
2. Enable and start `systemd-binfmt`:
```bash
sudo systemctl enable --now systemd-binfmt
```
3. Confirm the interpreters are registered:
```bash
ls /proc/sys/fs/binfmt_misc | grep -E "arm"
```
## Preparing a macOS Host (Podman machine)
The Podman machine VM runs Fedora CoreOS, which uses an immutable `rpm-ostree` base. `binfmt-support` does not exist here — use `qemu-user-static` with `systemd-binfmt`.
> [!warning]
> Every `machine-os` image is built using a temporary packit COPR repo that is deleted after the release ships. Running `rpm-ostree install` will fail with a GPG key 404 error until that repo is disabled:
> ```bash
> sudo sed -i 's/^enabled=1/enabled=0/g' /etc/yum.repos.d/podman-release-copr.repo
> ```
> This affects all image versions. The [[podman-machine-setup.yml|setup playbook]] handles this automatically. See the note below.
1. SSH into the machine:
```bash
podman machine ssh
```
2. Install `qemu-user-static` as a layered package and reboot to activate it. `--apply-live` cannot be used because `qemu-user-static` adds new directories:
```bash
sudo rpm-ostree install qemu-user-static
sudo systemctl reboot
```
3. Reconnect, enable `systemd-binfmt`, and register all handlers:
```bash
podman machine ssh
sudo systemctl enable --now systemd-binfmt
sudo podman run --rm --privileged docker.io/tonistiigi/binfmt --install all
```
4. Confirm the interpreters are registered:
```bash
ls /proc/sys/fs/binfmt_misc | grep -E "arm"
```
> [!note]
> `rpm-ostree` layered packages survive reboots but are lost if you `podman machine rm` and re-init. To make setup reproducible, use the setup playbook to re-apply everything automatically on a fresh machine:
> ```bash
> podman machine rm --force
> podman machine init --playbook ~/podman-machine-setup.yml --now
> ```
> See [[podman-machine-setup.yml]] for the full playbook.
## Podman Desktop (macOS/Windows) Notes
- macOS Podman Desktop already exposes a Linux VM with `linux/arm64` binfmt handlers. Run `podman build --platform linux/arm64 ...` directly.
- To add `linux/arm/v7` support, SSH into the machine (`podman machine ssh`) and follow the macOS host steps above.
- Windows users should rely on Podman Desktop instead of Docker Desktop; the service is automatically exposed to WSL2 after following the [Windows installation guide](https://podman.io/getting-started/installation#windows).
## Building a Raspberry Pi Image
Use the same containerfile you would on the Pi. Example:
```dockerfile
FROM --platform=linux/arm64 debian:bookworm-slim
RUN apt-get update && \
apt-get install -y --no-install-recommends build-essential && \
rm -rf /var/lib/apt/lists/*
WORKDIR /src
COPY hello.c ./
RUN gcc -o hello hello.c
CMD ["./hello"]
```
On x86 hosts run:
```bash
podman build --platform linux/arm64 -t hello-arm64 .
```
To target the older Pi Zero/1/2, change the `FROM` line to `--platform=linux/arm/v7` and make sure the image includes the appropriate cross-build toolchain (`crossbuild-essential-armhf` or `gcc-arm-linux-gnueabihf`).
## Verify the Architecture inside the Container
```bash
podman run --rm hello-arm64 uname -m && dpkg --print-architecture
podman run --platform linux/arm/v7 --rm <your-armv7-image> uname -m
```
Expect `aarch64` / `arm64` for new Pis and `armv7l` / `armhf` for the legacy builds.
## Performance
Emulated ARM builds are slightly slower than native Pi hardware but fast enough for CI pipelines and automated builders. Favor `linux/arm64` whenever a modern Pi is your target to minimize the emulation gap.
## Legacy Workflow (deprecated)
> [!warning]
> Pre-2017 guides downloaded the Raspberry Pi OS `.img`, mounted partitions, copied `qemu-arm-static`, and imported the filesystem as a container. That entire workflow is obsolete. Podman's `--platform` builds plus `qemu-user-static` replace it. Keep this old script in mind only for historical reference: https://raw.githubusercontent.com/jguiraudet/jguiraudet.github.io/master/_includes/bin/rpi-build-docker-img
## References
- Podman installation: [https://podman.io/getting-started/installation](https://podman.io/getting-started/installation)
- tonistiigi/binfmt helper: [https://github.com/tonistiigi/binfmt](https://github.com/tonistiigi/binfmt)