PXE boot an ARM64 VM in UTM on Apple Silicon. No ISO needed.
An Apple Silicon Mac (M1/M2/M3/M4), UTM installed, and network access.
Open UTM and create a virtual machine configured for network boot:
# In UTM: # 1. Click "+" → Virtualize → Other # 2. Skip Boot ISO (leave empty) → Continue # 3. Set RAM (4GB+) and CPU cores (2+) → Continue # 4. Set disk size (32GB) → Continue # 5. Save the VM # # Then edit VM settings: # 6. Network → Change to "Bridged (Advanced)" # 7. Select your active network interface (e.g., en0) # 8. UEFI Boot should be enabled by default
On any machine on the same network (your Mac works fine), run:
# bootstrap.env (mode 600, outside any repo): # BOOTSTRAP_TOKEN=<random, 32+ chars — same value as the Worker secret> # BOOTSTRAP_ALLOWED_MACS=<this machine's MAC, comma-separated for more> # BOOTSTRAP_CLIENT_CIDR=192.168.1.0/24 # From the repo root (reads the same variables from the environment): docker compose up # Or standalone: docker run --net=host --cap-add=NET_ADMIN \ --env-file ./bootstrap.env \ -e IPXE_SERVER_URL=https://ipxe.cloudcompute.com \ -e DHCP_RANGE=192.168.1.0 \ ghcr.io/fairchild/ipxe-bootstrap
This runs dnsmasq in proxy DHCP mode — it won't interfere with your existing router/DHCP — but it answers PXE only for allowlisted MACs, serves iPXE over TFTP, and runs a small boot proxy on :8080 that relays each machine's boot request to the Worker with the bootstrap bearer. The container fails closed if BOOTSTRAP_TOKEN or BOOTSTRAP_ALLOWED_MACS is missing.
Press Play in UTM. The VM will PXE boot through this chain:
# Boot chain: # 1. QEMU UEFI firmware (EDK2) → PXE DHCP request (answered only for an allowlisted MAC) # 2. dnsmasq detects ARM64 (client-arch=11) # 3. dnsmasq responds with ipxe-arm64.efi via TFTP # 4. iPXE does DHCP again, gets the non-secret bootstrap.ipxe via TFTP # 5. bootstrap.ipxe chains to the local boot proxy on :8080 # 6. Proxy adds the bearer, fetches /boot.ipxe from the Worker over HTTPS # 7. Boot menu appears — or the role/install script if this MAC is assigned # 8. Check-in recorded ✓
The VM's MAC is shown in UTM's network settings; put it in BOOTSTRAP_ALLOWED_MACS or the bootstrap ignores the VM entirely. The ephemeral RAM node boots after the countdown; arrow up to pick Debian ARM64.
UTM uses EDK2 firmware which supports HTTP Boot natively. Skip the bootstrap container entirely:
# In the VM's UEFI setup (press Escape at TianoCore logo): # 1. Device Manager → Network Device List → select MAC # 2. HTTP Boot Configuration # 3. Boot URI: http://ipxe.cloudcompute.com/boot/ipxe-arm64.efi # 4. Press F10 to save, then Reset
The VM fetches iPXE directly over HTTP — no TFTP, no proxy DHCP, no bootstrap container needed. Works with Shared Network (NAT) since it's a direct HTTP request.
PXE requires bridged networking. Check that the VM's network mode is set to Bridged (Advanced), not Shared Network. Select the correct network interface. Or try the HTTP Boot alternative (Step 5) which works with any network mode.
This usually means architecture mismatch — an x86_64 kernel was loaded on an ARM64 VM. Verify the boot menu shows ARM64-specific entries (e.g., "Debian 12 (Bookworm)" under Operating Systems with no sbnb listed).
The bootstrap container may not be running, may not be on the same network, or the VM's MAC may be missing from BOOTSTRAP_ALLOWED_MACS — dnsmasq ignores non-allowlisted clients silently. Check docker compose logs -f for the DHCP request and whether an offer followed it. Alternatively, use UEFI HTTP Boot (Step 5) which doesn't need the bootstrap container.
Older UTM/QEMU versions may not expose HTTP Boot in the UEFI setup. Update UTM to the latest version, or use the bootstrap container method (Steps 3-4).