Void Linux install to Framework 13

2026-05-17

Tag along with me as I install Void Linux onto a Framework 13 laptop.

This is not a guide. Think of this more like an adventurer chronicling their journey. Or like you’re reading an annotated shell history. Exciting stuff! Not really …


Beforehand

Download the Void Linux live-image installer then write it to a USB drive. I am using the base glibc image.

wget https://repo-default.voidlinux.org/live/current/void-live-x86_64-20250202-base.iso
dd if=void-live-x86_64-20250202-base.iso of=/dev/sdb status=progress

Run the installer

Log in as root into the live-image, then start the installer with void-installer.

Keyboard: select us

Network: eth0 with DHCP

Source: Network

Mirror: Default

Hostname: heavyarms

Locale: en_US.UTF-8

Timezone: America/New_York

RootPassword: hah! I’m not telling you!

UserAccount: komidore64; groups: wheel floppy dialout audio video cdrom optical storage network kvm input users xbuilder

BootLoader: /dev/nvme0n1; graphical boot loader? No

Partition:

/dev/nvme0n1p1      512M        EFI System
/dev/nvme0n1p2      8G          Linux Swap
/dev/nvme0n1p3      <the rest>  Linux filesystem

Filesystems:

/dev/nvme0n1p1      vfat        /boot/efi
/dev/nvme0n1p2      swap        swap
/dev/nvme0n1p3      ext4        /

Install!

Services to enable: dhcpd

Reboot.

Fresh system

From here we follow Void Documentation as closely as possible.

Log in as root. Less sudo we have to type.

Enable passwordless sudo:

visudo

Comment out the bottom line: # @includedir /etc/sudoers.d. Then uncomment a few lines above: %wheel ALL=(ALL:ALL) NOPASSWWD: ALL.

It’s a lot of typing to continually write out xbps-install, so I like to install xtools for the xi shortcut. We’ll also install void-docs locally for reference.

xbps-install xtools void-docs w3m

Manual Pages

Install cronie for daily execution of makewhatis.

xi cronie

# enable service
ln -s /etc/sv/cronie /var/service/

Additional man pages:

xi man-pages-devel man-pages-posix

Firmware

We have to enable Void’s nonfree repo to access Intel microcode.

xi void-repo-nonfree

xi intel-ucode binutils

Enable the pre- and post-installation hooks in the initramfs configuration.

xbps-reconfigure --force linux6.18

Logging

xi socklog-void

# enable services
ln -s /etc/sv/socklog-unix /var/service/
ln -s /etc/sv/nanoklogd /var/service/

usermod -aG socklog komidore64

Solid State Drives

Create /etc/cron.weekly/fstrim with the following contents:

#!/bin/sh

fstrim /

Make the script executable:

chmod u+x /etc/cron.weekly/fstrim

AppArmor

xi apparmor

Append apparmor=1 security=apparmor to the kernel commandline.

vi /etc/default/grub
update-grub

Set the APPARMOR variable to “enforce”.

vi /etc/default/apparmor

Reboot.

Log in as root. Confirm the new commandline args are present.

cat /proc/cmdline

Confirm that AppArmor is enabled:

aa-enabled
# => Yes

Date and Time

Install and enable Chrony:

xi chrony
ln -s /etc/sv/chronyd /var/service/

Power Management

Install and enable tlp:

xi tlp smartmontools
ln -s /etc/sv/tlp /var/service/

NetworkManager

I find NetworkManager easier to work with than dhcpd and wpa_supplicant for a laptop setting. NetworkManager needs dbus.

# enable service
ln -s /etc/sv/dbus /var/service/

Install NetworkManager before we disable dhcpd.

xi NetworkManager polkit

sv down /var/service/dhcpd

# enable NetworkManager
ln -s /etc/sv/NetworkManager /var/service/

# disable dhcpd once we've confirmed NetworkManager is working
rm /var/service/dhcpd

Session and Seat Management

xi seatd
ln -s /etc/sv/seatd /var/service/

usermod -aG _seatd komidore64
xi dumb_runtime_dir

Uncomment session optional pam_dumb_runtime_dir.so in PAM configuration.

vi /etc/pam.d/system-login

Reboot.

Log in as komidore64. Confirm dumb_runtime_dir is working as expected:

echo $XDG_RUNTIME_DIR
# => /run/user/1000

Log in as root.

Graphics Drivers – Intel

Install lots of graphics related packages:

xi linux-firmware-intel mesa-dri vulkan-loader mesa-vulkan-intel intel-video-accell libva-intel-driver intel-gpu-tools

Wayland

Install the compositor, terminal, bar, launcher, a few utilities, and a browser.

xi niri foot Waybar xwayland-satellite wmenu mako swaybg swaylock xdg-utils firefox neovim

Add some environment variables for native applications that need to know we’re using Wayland. Add the following environment variables to /etc/profile.

QT_QPA_PLATFORM=wayland
ELM_DISPLAY=wl
SDL_VIDEODRIVER=wayland

Log in as komidore64. Edit the default Niri config to use foot and wmenu:

cp /usr/share/examples/niri/default-config.kdl ~/.config/niri/config.kdl
nvim ~/.config/niri/config.kdl

Confirm that Niri will start without error:

dbus-run-session niri --session

Fonts

Log in as root.

xi dejavu-fonts-ttf noto-fonts-ttf noto-fonts-cjk noto-fonts-emoji nerd-fonts-symbols-ttf

PipeWire

xi pipewire libjack-pipewire wiremix

Configure PipeWire to launch WirePlumber directly and setup PipeWire’s PulseAudio interface.

mkdir -p /etc/pipewire/pipewire.conf.d
ln -s /usr/share/examples/wireplumber/10-wireplumber.conf /etc/pipewire/pipewire.conf.d/
ln -s /usr/share/examples/pipewire/20-pipewire-pulse.conf /etc/pipewire/pipewire.conf.d/

Override the library provided by libjack to point to PipeWire.

echo "/usr/lib/pipewire-0.3/jack" > /etc/ld.so.conf.d/pipewire-jack.conf
ldconfig

Reboot.

Log in as root. Install a bunch of multimedia codecs.

xi gstreamer1 gstreamer1-pipewire gst-plugins-bad1 gst-plugins-base1 gst-plugins-good1 gst-plugins-ugly1

Bluetooth

xi bluez libspa-bluetooth
ln -s /etc/sv/bluetoothd /var/service/

Afterwards

Misc

xi kanshi brightnessctl fish-shell lf fzf starship podman bat tig lazygit delta broot aerc jq yq wget

Change the user’s default shell

chsh -s$(which fish) komidore64

Treesitter

xi tree-sitter-cli tree-sitter-devel gcc

NetworkManager WIFI

NetworkManager is capable of detecting what DNS tooling is installed on a system, and configuring itself accordingly. For whatever reason that did not go as planned on my Framework.

This manifested in being able to connect to wireless networks, but addressed would never resolve. For a spell I first thought I was encountering networks that were full (public spaces, etc) but then it occurred at multiple locations which led me to reconsider, “No. It’s probably something on my Framework.” Logs showed that NM was unable to set DNS configuration for the network.

I was able to restore DNS with the following NetworkManager config (/etc/NetworkManager/NetworkManager.conf) changes:

[main]
dns=default
rc-manager=symlink

We made it. Thanks for tagging along for the ride!