hak8or afeec53441 firmware: add linux-firmware-rtl_nic for RTL8156B USB NIC support
The RTL8156B USB 2.5GbE NIC uses the mainline r8152 driver
(drivers/net/usb/r8152.ko.gz), which is unaffected by the
non-Intel ethernet vendor pruning step — that only removes
subdirectories under drivers/net/ethernet/.

However, the r8152 driver requests rtl8156b-2.fw at probe time,
which was absent because only linux-firmware-intel and
linux-firmware-i915 were installed.  Add linux-firmware-rtl_nic
to supply it.  The firmware files are pre-compressed .fw.zst, so
the size impact is ~57 KB on the final initramfs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-19 22:43:33 -05:00

Alpine Bare-Metal Homelab OS

Summary

This is a largely (though not wholly, like this summary chunk) AI driven series of scripts/tools used to generate a initrd and vmlinuz using alpine as the userspace, for being ran on n100 nodes. We rely on the nodes booting with iPXE (the ipxe script is also created by this project), and an RB4011 used to hold the vmlinuz and initrd. This is so we can use nodes as "cattle" instead of "pets", so any new hardware that boots into ipxe will automatically join the "herd".

We try to keep the initrd as small as possible so nodes both boot fast, and so it fits on small space on the RB4011. As of this commit, it's a meager ~159 MB initrd and ~13MB vmlinuz. This contains a VM runner, podman for containers, ssh server, zfs (we run from RAM but one node wants ZFS), etc.

The RTL8156B USB 2.5GbE NIC is supported via the mainline r8152 kernel module (in drivers/net/usb/, safe from the non-Intel ethernet vendor pruning step). Its firmware (rtl8156b-2.fw) is provided by linux-firmware-rtl_nic, which adds only ~57 KB to the image (files are pre-compressed .fw.zst).

We have a bash driven initrd/etc generation, with configuration in config.sh for things like what alpine version.

Build

To create the initrd and vmlinuz and ipxe script;

# First build (downloads ~500 MB, cached for offline rebuilds)
./build.sh

# Rebuild initramfs without re-downloading packages
./build.sh --no-rootfs

# Override boot server URL for the iPXE script
BOOT_SERVER_URL=http://10.0.0.1 ./build.sh

To locally test (manually feeding vmlinuz and initrd to qemu);

# Text mode (serial console) — press Ctrl-a x to quit
./start_qemu.sh

# Graphical mode
./start_qemu.sh --graphical

# More RAM / CPUs
./start_qemu.sh --memory 4G --smp 4

Offline / Reproducible Builds

The cache/ directory stores every downloaded artifact:

  • cache/apk-tools/apk.static binary and Alpine signing keys
  • cache/keys/ — Alpine APK signing keys
  • cache/apk-packages/ — All downloaded .apk files

After a successful online build, copy the entire project directory (including cache/) to an air-gapped machine and rebuild without internet.

Overlay Files

Drop files into overlay/ to include them verbatim in the rootfs. The directory structure mirrors /. For example:

overlay/etc/ssh/authorized_keys  ->  /etc/ssh/authorized_keys
overlay/root/.bashrc             ->  /root/.bashrc

Space Savings

The initrd started at ~181 MB (alpine-base + firecracker), grew to ~229 MB after adding Nomad, and is now back down after the analysis below. All measurements are on a 473 MB uncompressed cpio of the rootfs.

Compression

Config Size vs gzip-9 vs zstd-19 Time
gzip -9 (reference) 266 MB baseline +16% 32s
zstd -1 -T0 277 MB +4% +21% <1s
zstd -6 -T0 259 MB -3% +13% <1s
zstd -9 -T0 246 MB -8% +7% 1s
zstd -15 -T0 244 MB -8% +7% 4s
zstd -19 -T0 (was default) 229 MB -14% 0% 14s
zstd -22 -T0 222 MB -17% -3% 148s
zstd -19 -T0 --long=24 227 MB -15% -1% 25s
zstd -19 -T0 --long=25 226 MB -15% -1% 26s
zstd -19 -T0 --long=26 225 MB -15% -2% 28s
zstd -19 -T0 --long=27 (current) 223 MB -16% -3% 29s
zstd -22 -T0 --long=27 222 MB -17% -3% 144s

--long=27 extends the match window to 128 MiB. It saves 6 MB vs the plain -19 default for only 2x compression time, and matches -22 --long=27 for a fraction of the cost. -22 alone barely beats -19 --long=27 and costs 10x longer.

Pre-compression rootfs stripping

These are rootfs savings (before compression). Kernel modules and firmware files are already zstd-compressed by Alpine, so stripping them saves roughly their full uncompressed size in the final initrd.

What Savings Rationale
strip --strip-debug on nomad binary ~23 MB HashiCorp ships with DWARF debug info
strip --strip-debug on firecracker + jailer ~1.5 MB Also shipped with debug info
kernel/drivers/net/wireless ~11 MB N100 has no WiFi radio
lib/firmware/i915 ~9 MB GPU driver (kernel/drivers/gpu) already stripped
intel/vsc + intel/ipu ~8 MB Vision/camera subsystems, not on a headless server
Intel Bluetooth (intel/ibt-*) ~5 MB No BT use on a server node
Non-Intel ethernet vendors ~5.5 MB Keep only ethernet/intel (e1000e/igb/ixgbe)
Legacy filesystems (reiserfs, ocfs2, hfs, jfs, …) ~2.5 MB ext4, overlayfs, btrfs, xfs, fat, nfs, fuse, squashfs kept
net/wireless, net/tipc, net/rxrpc, net/x25 ~1.5 MB Unused network protocol stacks
intel/avs + intel/ish ~0.9 MB Audio DSP + sensor hub, not on a server
usr/share/bash-completion ~1.3 MB Shell completions not needed in initramfs
Total pre-compression ~69 MB off rootfs → ~5565 MB off final initrd

Original Prompt

The following is the original prompt that initiated this project, preserved verbatim for bread crumb purposes. Note we diverged from this over time, but much of the original philosophy still stands.

I want to use Alpine as the OS running bare metal on a few Intel N100 based nodes in my homelab. Thing is, I want all the nodes to boot using iPXE, and make use of alpine because it allows for an extremely minimal base to start from. The bare metal OS will be responsible for starting up VM's (lets assume firecracker as the VM execution engine) and containers (podman as the execution engine). Each N100 node must also have an OpenSSH server running, a git client, and use bash as the shell. Ah, and support for the zfs file system. I want to be able to generate images which can be used by iPXE to boot, and manually specify what packages to have embedded in Alpine. Let me specify the Alpine release. I want to be able to reproduce this without an internet connection, so ensure there is some caching mechanism in place (a CACHE directory for example) that contains everything needed to create the image. Lastly, add a "start_qemu" (or firecracker if that would be better/simpler for this purpose) solely to ensure the resulting initrd and vmlinux files passed to iPXE actually work (ideally in a text only mode, but allow for graphical). Oh, and create a CLAUDE.md meant for this type of project, which includes a copy of this prompt word for word (for auditing purposes).

Description
No description provided
Readme 257 KiB
v0.1.2 Latest
2026-02-18 04:28:43 +00:00
Languages
Shell 100%