Skip to content

Instantly share code, notes, and snippets.

@robmcmullen
Last active August 2, 2026 05:29
Show Gist options
  • Select an option

  • Save robmcmullen/7992b0e6208c150dd94148b473aca5c0 to your computer and use it in GitHub Desktop.

Select an option

Save robmcmullen/7992b0e6208c150dd94148b473aca5c0 to your computer and use it in GitHub Desktop.
Alpine Linux run from RAM

Run Alpine Linux from RAM as a desktop OS

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.

Create Boot Disk

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/sdX1

Remove 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 -d

and reboot.

Install Packages

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/community

and 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-shim

ZFS

If using ZFS, add additional packages:

apk add zfs

Mount any existing ZFS partitions on the NVMe drive:

zpool import -a
zfs load-key HOMEPOOL
zfs mount -a

Having 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

ext4

If using ext4, add:

apk add e2fsprogs

and format with:

mkfs.ext4 /dev/sda2

Edit /etc/fstab to include:

/dev/sda2 /opt ext4 defaults 0 1

Probably a good idea to reboot:

lbu commit -a
reboot

to check that /opt is mounted automatically. Create the home directory on the /opt filesystem:

mkdir /opt/home

Desktop Environment

Chose 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.

XFCE issues

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 -d

Also 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

Networking

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

Audio

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

Video

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.

Option 1

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.

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.

Wifi

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

Local AI Model

Qemu

apk add qemu-system-x86_64 qemu-modules libvirt libvirt-qemu
adduser $USER qemu
adduser $USER kvm

Misc

Cleanup firmware

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...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment