The Problem with State

Filippo Valsorda's NAS, "frood," runs entirely from an initramfs — no root filesystem, no overlay, no package manager at boot. The entire Alpine Linux system is packed into a cpio archive loaded by the kernel. Every boot is a fresh start.

Why go to such lengths? Valsorda quotes Graham Christensen's "Erase your darlings" philosophy: systems accumulate undocumented state over time. Quick fixes like touch /etc/ipsec.secrets become forgotten steps that haunt you during upgrades. Alpine's default "diskless mode" uses lbu(1) to manage overlay files, but Valsorda found it brittle — it broke multiple times over the past year due to filesystem detection issues or missing apks. The boot process depends on the package manager, which is fragile.

How It Works

The build process is remarkably simple. It uses alpine-make-rootfs (a ~500-line script) to create a rootfs, then packages everything except /boot into an initramfs:

cd "$ROOTFS_DEST"
find . -path "./boot" -prune -o -print | cpio -o -H newc | gzip > "$ROOTFS_DEST/boot/initramfs-lts"

Key packages include alpine-base, linux-lts, and linux-firmware-none (to avoid the 500MB firmware blob). The setup script configures OpenRC runlevels and sets the root password (a real hash is in the source). The root skeleton drops files directly — for example, root/etc/local.d/ for boot scripts, root/etc/network/interfaces for networking, and SSH host keys.

Persistence for the Unavoidable

Two things need persistence: the RNG seed and Tailscale state. Both are stored on a USB drive mounted by UUID:

UUID=B61B-19E7   /media/usb   vfat   noatime,rw,fmask=177 0 0

Tailscale is configured with -state /media/usb/persist/tailscaled.state and seedrng writes to /media/usb/persist/seedrng.

Unified Kernel Image

In 2025, Valsorda switched to a Unified Kernel Image (UKI) assembled by ukify, loaded directly by UEFI firmware from EFI/BOOT/BOOTAA64.EFI. No bootloader. Deployment is a single rsync:

rsync images/$image root@frood:/media/usb/EFI/BOOT/BOOTAA64.EFI

The UKI includes kernel, initramfs, and command line rdinit=/sbin/init console=tty1 console=ttyAMA0.

Testing with QEMU

A key advantage: you can test the exact same image in QEMU, including persistence:

qemu-system-aarch64 -M virt -cpu cortex-a72 -m 4G -nographic \
  -bios QEMU_EFI.fd -kernel "images/$image" \
  -drive file=usb_disk.img,if=virtio,format=raw

Tailscale config on the USB drive makes the QEMU instance appear as a separate device, allowing SSH access for testing.

Adding a Service

Valsorda demonstrates adding a simple Go status server. Build all Go binaries from a local module:

go build -o "$ROOTFS_DEST/usr/local/bin/" ./cmd/...

Then create an OpenRC init script root/etc/init.d/srvmonitor and add rc-update add srvmonitor default in setup.sh. The server listens on port 80 via Tailscale IP and serves scripts from /etc/monitor.d/.

The Trade-offs

This approach isn't for everyone. Secrets management is unsolved — currently ZFS passkeys and .gitignored files. Valsorda mentions possible future solutions: YubiKey with age-plugin-yubikey, or TPM-based Secure Boot. The setup also requires familiarity with Alpine's packaging and OpenRC.

But the benefits are clear: declarative, git-tracked system state; trivial rollback by booting an older UKI; no SD card wear; and a system that's "delightful" to maintain. The entire build is open source in Valsorda's repository.

What You Should Do Now

If you're tired of configuration drift and want a system that's truly ephemeral, fork Valsorda's build scripts and adapt them to your hardware. Start with a QEMU test to get comfortable. You'll need Alpine knowledge and a willingness to write shell scripts instead of using a DSL.