The goal is to have a system on an external USB drive that loads the entire OS to RAM and runs from there. The OS will include a full a graphical desktop (XFCE in this example). Home directories and other persistent storage will be on filesystems on internal laptop block devices.
Caution
Rule #1: Any changes to the OS or packages added by apk add must be followed by lbu commit -d to save the changes to the OS partition. You will lose work by forgetting to call lbu commit -d. See below for examples.
Using the Alpine Extended ISO, boot from it and prepare a new device to use as the new bootable media.
This can be a USB stick or a hard drive partition.
Note its device entry in the /media directory, in this example /media/sdb.
This will be the source used for the setup-bootable command below. Use mdev -s to reload the /dev
directory, then find the USB drive using dmesg.
Install fdisk and format the drive with one Linux partition containing the entire contents of the drive,
and make it bootable. Then install a copy of the Alpine ISO:
apk add util-linux
fdisk /dev/sdX # and do the above stuff here
mkfs.vfat /dev/sdXY
setup-bootable /media/sdb /dev/sdX1Remove the original Alpine ISO drive and reboot using the new drive. Find the name of the install drive using
df -h, for example /dev/sda1.
Once booted into the environment from the new drive, you most likely will need wired internet
as some drivers for newer hardware are not included on the Alpine ISO.
Run setup-alpine. In the Disk & Install section, it may ask:
No disks available. Try boot media /media/sda1? (y/n) [n]. If it does, type n.
For Which disk(s) would you like to use? (or '?' for help or 'none' use none, which flags this to a run
from RAM system. For Enter where to store configs ('floppy', 'sda1', 'usb' or 'none') [sda1] use sda1. If sda1 does not appear, choose usb, and you may have to edit /etc/fstab manually.
Note: don't add a user through the setup-alpine script, otherwise the home directory will be backed up with lbu.
The home directories for this install will be on another partition.
lbu commit -dand reboot.
Change /etc/apk/repositories to use https repositories:
/media/usb/apks
https://mirrors.ocf.berkeley.edu/alpine/v3.24/main
https://mirrors.ocf.berkeley.edu/alpine/v3.24/communityand rebuild apk database before installing some initial packages we will use:
apk update
apk add htop util-linux rsync wget pciutils ripgrep fd powertop file git neovim less doas doas-sudo-shimIf using ZFS, add additional packages:
apk add zfsMount any existing ZFS partitions on the NVMe drive:
zpool import -a
zfs load-key HOMEPOOL
zfs mount -aHaving difficulties getting a password prompt at boot.
There exists an init script zfs-load-key, but it doesn't work for a prompt, it only works for a
passkey stored in a file. I even modified the init script to remove the check for a prompt, but it
doesn't ask for a prompt at the terminal, responds with:
* Load key for HOMEPOOL ...
Key load error: Incorrect key provided for 'HOMEPOOL'.
If you want some inside baseball, I think the way the script is coded is by calling the
zfs load-key -L prompt command in a subshell, meaning the standard input is /dev/null.
Finally got this to work by creating a custom openrc script, zfs-import-key-prompt, see https://gist.github.com/robmcmullen/902e9c9cbc2461bb595cf644f6f932da
If using ext4, add:
apk add e2fsprogsand format with:
mkfs.ext4 /dev/sda2Edit /etc/fstab to include:
/dev/sda2 /opt ext4 defaults 0 1Probably a good idea to reboot:
lbu commit -a
rebootto check that /opt is mounted automatically. Create the home directory on the /opt filesystem:
mkdir /opt/homeChose the desktop environment and add a desktop user with:
setup-desktop
USER=username
mkdir /opt/home
adduser -h /opt/home/$USER -s /bin/ash $USER
addgroup $USER netdev
If logging in results in back to login screen, you probably have permissions problems in the home directory or added the user before setting up the desktop.
Thunar is not showing USB devices when they are plugged in, but gvfs is installed. Trying:
rc-update add polkit
rc-service polkit start
lbu commit -dAlso tried:
addgroup $USER disk
but still nothing working. Looks like fuse is missing?
apk add fuse-openrc udisks2 gvfs-mtp gvfs-smb gvfs-fuse gvfs-nfs gvfs-archive
rc-service fuse start
rc-update add fuse
I want to disable IPV6 entirely because it seems harder to lock down. Added /etc/sysctl.d/local.conf:
# Force IPv6 off
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
net.ipv6.conf.eth0.disable_ipv6 = 1
net.ipv6.conf.wlan0.disable_ipv6 = 1
and for good measure, commented out ipv6 from /etc/modules
My machine needs the Intel SOF firmware, which creates a new problem:
# apk add sof-firmware
(1/1) Installing sof-firmware (2025.12.2-r0)
ERROR: sof-firmware-2025.12.2-r0: failed to extract lib/firmware/intel/sof-ace-tplg: Read-only file system
ERROR: sof-firmware-2025.12.2-r0: failed to extract lib/firmware/intel/sof-ipc4-lib/lnl/B36EE4DA-006F-47F9-A06D-FECBE2D8B6CE.bin: No such file or directory
...
Turns out that /lib/firmware is mounted in a read-only using the modloop option in the boot command. This can be fixed by adding an
overlayfs to the boot options:
mount -o remount,rw /media/usb
sed -i -e 's/squashfs,/squashfs,overlay,/' /media/usb/boot/grub/grub.cfg
Then reboot and the apk add should succeed:
apk add sof-firmware
lbu commit -d
Note
There's also this option if you want to avoid an overlay and add files to the directory mounted by modloop.
I'm using PipeWire:
apk add pipewire wireplumber pipewire-pulse pipewire-alsa pavucontrol xfce4-pulseaudio-plugin
lbu commit -d
My device has an Intel Xe integrated GPU and a dedicated NVIDIA GPU. My ultimate goal is to run a local AI model on one of the GPUs.
Since NVIDIA is unlikely to compile drivers for musl, I will try running NVIDIA for my graphics, and use the Intel Xe hardware as the AI GPU.
apk add mesa-dri-gallium mesa-va-gallium mesa-vulkan-nouveau
lbu commit -d
My NVIDIA hardware is identified as NV197, which is unsupported by nouveau.
time passes
Having problems. Trying to disable i915 also disables xe, using module_blacklist=i915 requires nomodeset or boot process gets stuck at uevents (really, it's trying the modesetting kernel and hanging, apparently.)
more time passes
Grrr. Can't get this working. Trying Option 2.
Use the Intel Xe integrated GPU for graphics, and run NVIDIA in Qemu with the AI model on some glibc distro with hardware passthrough. Blocklisted the nouveau driver in the early boot process by editing /media/usb/boot/grub/grub.cfg to read:
set timeout=5
menuentry "Linux lts" {
linux /boot/vmlinuz-lts modules=loop,squashfs,overlay,sd-mod,usb-storage module_blacklist=nouveau
initrd /boot/intel-ucode.img /boot/amd-ucode.img /boot/initramfs-lts
}
after doing mount -o remount,rw /media/usb of course. Without anything in the /etc/X11/xorg.conf.d directory, graphics do work, but it appears it's using software rendering:
$ mpv test.mp4
MESA: warning: Could not get intel_device_info.
[vo/gpu-next/libplacebo] EnumeratePhysicalDevices(inst, &num, NULL): VK_ERROR_INITIALIZATION_FAILED (../src/vulkan/context.c:1007)
[vo/gpu-next/libplacebo] Found no suitable device, giving up.
[vo/gpu-next/libplacebo] Failed initializing vulkan device
libEGL warning: DRI3 error: Could not get DRI3 device
libEGL warning: Ensure your X server supports DRI3 to get accelerated rendering
[vo/gpu-next/opengl] Suspected software renderer or indirect context.
[vo/gpu-next/drm] VT_GETMODE failed: Not a tty
[vo/gpu-next/drm] Failed to set up VT switcher. Terminal switching will be unavailable.
MESA: warning: Could not get intel_device_info.
MESA: warning: Could not get intel_device_info.
[vo/gpu-next/drm] Failed to acquire DRM master: Permission denied
[vo/gpu-next/drm] Failed to commit ModeSetting atomic request: Permission denied
[vo/gpu-next/opengl] Failed to set CRTC for connector 262: Permission denied
So, some permission denied messages, adding user to video group and see if that changes things.
UPDATE: nope. However, I just noticed that I had not installed linux-firmware-i915, so maybe that's the problem.
UPDATE: yep, that was the problem. Yay.
My wifi fails to load at boot, apparently because a firmware file is not included?
[ 39.368665] iwlwifi 0000:00:14.3: Detected Intel(R) Wi-Fi 6E AX211 160MHz
[ 39.368693] iwlwifi 0000:00:14.3: Direct firmware load for iwlwifi-ma-b0-gf-a0-89.ucode failed with error -2
[ 39.368695] iwlwifi 0000:00:14.3: no suitable firmware found!
[ 39.368696] iwlwifi 0000:00:14.3: iwlwifi-ma-b0-gf-a0-89 is required
[ 39.368697] iwlwifi 0000:00:14.3: check git://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git
However, the file exists in linux-firmware-intel:
# apk manifest /media/usb/apks/x86_64/linux-firmware-intel-20260519-r0.apk | grep ma-b0-gf-a0-89
sha1:75ee21a03ca8202cfaa4fdf533366be9a48d4253 lib/firmware/intel/iwlwifi/iwlwifi-ma-b0-gf-a0-89.ucode.zst
so I don't know why it's not loading? Maybe it has to exist in the initrd? But the sof firmware gets loaded, so...
UPDATE: apparently I forgot to do an lbu commit -d one time after installing linux-firmware, so the file was downloaded in my apk cache but not loaded on install. See Rule #1.
apk add networkmanager networkmanager-wifi wpa_supplicant
adduser $USER plugdev
Add the config file /etc/NetworkManager/NetworkManager.conf to read:
[main]
dhcp=internal
plugins=ifupdown
[ifupdown]
managed=true
[device]
wifi.backend=wpa_supplicant
wifi.scan-rand-mac-address=yes
and add to services while removing old networking services (if applicable):
rc-update add networkmanager default
rc-update del networking boot
rc-update del wpa_supplicant boot
apk add qemu-system-x86_64 qemu-modules libvirt libvirt-qemu
adduser $USER qemu
adduser $USER kvm
There's almost 800MB of firmware files installed, which is a good third of the entire image.
$ du -hc /media/usb/apks/x86_64/linux-firmware*
16.0K /media/usb/apks/x86_64/linux-firmware-20260519-r0.apk
32.0K /media/usb/apks/x86_64/linux-firmware-3com-20260519-r0.apk
...
16.0K /media/usb/apks/x86_64/linux-firmware-yam-20260519-r0.apk
16.0K /media/usb/apks/x86_64/linux-firmware-yamaha-20260519-r0.apk
757.8M total
From here, setting a kernel boot parameter in /media/usb/boot/grub/grub.cfg:
dyndbg="file drivers/base/firmware_loader/main.c +fmp"
that is supposed to list the firmware files that are loaded. We'll see...
- entire system run from initramfs: https://words.filippo.io/frood/