Skip to content

Void Linux Single disk UEFI

Zach Dykstra edited this page Nov 5, 2021 · 30 revisions

This guide can be used to install Void onto a single disk with with or without ZFS encryption.

It assumes the following:

  • Your system uses UEFI to boot
  • Your system is x86_64
  • You will use glibc as your system libc.
  • /dev/sda is the onboard SSD, used for both ZFS and EFI
  • You're mildly comfortable with ZFS, EFI and discovering system facts on your own (lsblk, dmesg, gdisk, ...)

ZFSBootMenu does not require glibc and is not restricted to x86_64. If you are comfortable installing Void Linux on other architectures or with the musl libc, you can adapt the instructions here to your desired configuration.

When following this guide, if a section requires different steps to be taken for a system with encryption versus a system without encryption, the steps are behind a Encrypted or Unencrypted collapsible header.

Download the latest hrmpf, write it to USB drive and boot your system in EFI mode. You can confirm you've booted in EFI mode by running efibootmgr. Make sure you have the date set correctly and are connected to the internet.

ZFS prep work

Build and load ZFS modules

xbps-reconfigure -a
modprobe zfs

Generate /etc/hostid

zgenhostid

Store your pool passphrase in a key file

Encrypted

echo 'SomeKeyphrase' > /etc/zfs/zroot.key
chmod 000 /etc/zfs/zroot.key

SSD prep work

Create an EFI partition on /dev/sda

Encrypted and unencrypted

bash-5.0# gdisk /dev/sda
GPT fdisk (gdisk) version 1.0.4

Partition table scan:
  MBR: not present
  BSD: not present
  APM: not present
  GPT: not present

Creating new GPT entries in memory.

Command (? for help): o
This option deletes all partitions and creates a new protective MBR.
Proceed? (Y/N): y

Command (? for help): n
Partition number (1-128, default 1): 1
First sector (34-1000215182, default = 2048) or {+-}size{KMGTP}: 
Last sector (2048-1000215182, default = 1000215182) or {+-}size{KMGTP}: +512M
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): EF00
Changed type of partition to 'EFI System'

Command (? for help): n
Partition number (2-128, default 2): 
First sector (34-1000215182, default = 1050624) or {+-}size{KMGTP}: 
Last sector (1050624-1000215182, default = 1000215182) or {+-}size{KMGTP}: 
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): 
Changed type of partition to 'Linux filesystem'

Command (? for help): w

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!

Do you want to proceed? (Y/N): y
OK; writing new GUID partition table (GPT) to /dev/sda.
The operation has completed successfully.
bash-5.0#

ZFS pool creation

Create the zpool

Encrypted

zpool create -f -o ashift=12 \
 -O compression=lz4 \
 -O acltype=posixacl \
 -O xattr=sa \
 -O relatime=on \
 -O encryption=aes-256-gcm \
 -O keylocation=file:///etc/zfs/zroot.key \
 -O keyformat=passphrase \
 -o autotrim=on \
 -m none zroot /dev/sda2

It's out of the scope of this guide to cover all of the pool creation options used - feel free to tailor them to suit your system. However, the following options need to be addressed:

  • encryption=aes-256-gcm - You can adjust the algorithm as you see fit, but this will likely be the most performant on modern x86_64 hardware.
  • keylocation=file:///etc/zfs/zroot.key - This sets our pool encryption passphrase to the file /etc/zfs/zroot.key, which we created in a previous step. This file will live inside your initramfs stored ON the ZFS boot environment.
  • keyformat=passphrase - By setting the format to passphrase, we can now force a prompt for this in zfsbootmenu. It's critical that your passphrase be something you can type on your keyboard, since you will need to type it in to unlock the pool on boot.
Unencrypted

zpool create -f -o ashift=12 \
 -O compression=lz4 \
 -O acltype=posixacl \
 -O xattr=sa \
 -O relatime=on \
 -o autotrim=on \
 -m none zroot /dev/sda2

Create our initial file systems

zfs create -o mountpoint=none zroot/ROOT
zfs create -o mountpoint=/ -o canmount=noauto zroot/ROOT/void
zfs create -o mountpoint=/home zroot/home

NOTE: It is important to set the property canmount=noauto on any file systems with mountpoint=/ (that is, on any additional boot environments you create). Without this property, Void will attempt to automount all ZFS file systems and fail when multiple file systems attempt to mount at /; this will prevent your system from booting. Automatic mounting of / is not required because the root file system is explicitly mounted in the boot process.

Also note that, unlike many ZFS properties, canmount is not inheritable. Therefore, setting canmount=noauto on zroot/ROOT is not sufficient, as any subsequent boot environments you create will default to canmount=on. It is necessary to explicitly set the canmount=noauto on every boot environment you create.

Export, then re-import with a temporary mountpoint of /mnt

Encrypted

zpool export zroot
zpool import -N -R /mnt zroot
zfs load-key -L prompt zroot
zfs mount zroot/ROOT/void
zfs mount zroot/home
Unencrypted

zpool export zroot
zpool import -N -R /mnt zroot
zfs mount zroot/ROOT/void
zfs mount zroot/home

Verify that everything is mounted correctly

# mount | grep mnt
zroot/ROOT/void on /mnt type zfs (rw,relatime,xattr,posixacl)
zroot/home on /mnt/home type zfs (rw,relatime,xattr,posixacl)

Install Void

Adjust the mirror / libc / package selection as you see fit

XBPS_ARCH=x86_64 xbps-install -S -R https://mirrors.servercentral.com/voidlinux/current -r /mnt base-system vim efibootmgr gptfdisk linux5.10 linux5.10-headers

Copy our files into the new install

Encrypted

cp /etc/hostid /mnt/etc
cp /etc/resolv.conf /mnt/etc/
mkdir /mnt/etc/zfs
cp /etc/zfs/zroot.key /mnt/etc/zfs
Unencrypted

cp /etc/hostid /mnt/etc
cp /etc/resolv.conf /mnt/etc/

Chroot into the new OS

mount -t proc proc /mnt/proc
mount -t sysfs sys /mnt/sys
mount -B /dev /mnt/dev
mount -t devpts pts /mnt/dev/pts
chroot /mnt /bin/bash

Basic Void configuration

Set the keymap, timezone and hardware clock

cat << EOF >> /etc/rc.conf
KEYMAP="us"
TIMEZONE="America/Chicago"
HARDWARECLOCK="UTC"
EOF

Configure your glibc locale

cat << EOF >> /etc/default/libc-locales
en_US.UTF-8 UTF-8
en_US ISO-8859-1
EOF
xbps-reconfigure -f glibc-locales

Set a root password

passwd

ZFS Configuration

Install ZFS

xbps-install -S
xbps-install zfs

To more quickly discover and import pools on boot, we need to set a pool cachefile

zpool set cachefile=/etc/zfs/zpool.cache zroot

Configure our default boot environment

zpool set bootfs=zroot/ROOT/void zroot

Configure Dracut to load ZFS support

Encrypted

cat << EOF > /etc/dracut.conf.d/zol.conf
nofsck="yes"
add_dracutmodules+=" zfs "
omit_dracutmodules+=" btrfs "
install_items+=" /etc/zfs/zroot.key "
EOF
Unencrypted

cat << EOF > /etc/dracut.conf.d/zol.conf
nofsck="yes"
add_dracutmodules+=" zfs "
omit_dracutmodules+=" btrfs "
EOF

Rebuild the initramfs

xbps-reconfigure -f linux5.10

Install and configure ZFSBootMenu

  • Assign command-line arguments to be used when booting the final kernel. Because ZFS properties are inherited, assign the common properties to the ROOT dataset so all children will inherit common arguments by default.
zfs set org.zfsbootmenu:commandline="ro quiet" zroot/ROOT

Create a vfat filesystem

mkfs.vfat -F32 /dev/sda1

Create an fstab entry and mount

cat << EOF >> /etc/fstab
$( blkid | grep /dev/sda1 | cut -d ' ' -f 2 ) /boot/efi vfat defaults,noauto 0 0
EOF
mkdir /boot/efi
mount /boot/efi

Install ZFSBootMenu

From source

xbps-install zfsbootmenu

Enable zfsbootmenu image creation

Edit /etc/zfsbootmenu/config.yaml and set:

  • ManageImages: true under the Global section
  • Versions: 3 and Enabled: true under the Components section

See generate-zbm(5) for more details.

Sample /etc/zfsbootmenu/config.yaml

Global:
  ManageImages: true
  BootMountPoint: /boot/efi
  DracutConfDir: /etc/zfsbootmenu/dracut.conf.d
Components:
  ImageDir: /boot/efi/EFI/void
  Versions: 3
  Enabled: true
  syslinux:
    Config: /boot/syslinux/syslinux.cfg
    Enabled: false
EFI:
  ImageDir: /boot/efi/EFI/void
  Versions: 2
  Enabled: false
Kernel:
  CommandLine: ro quiet loglevel=0

Disable GPU drivers

echo 'omit_drivers+=" amdgpu radeon nvidia nouveau i915 "' >> /etc/zfsbootmenu/dracut.conf.d/drivers.conf

Generate the initial ZFSBootMenu initramfs

xbps-reconfigure -f zfsbootmenu
zfsbootmenu: configuring ...
Creating ZFS Boot Menu 0.8.1_1, with vmlinuz 5.4.15_1
Found 0 existing images, allowed to have a total of 3
Created /boot/efi/EFI/void/vmlinuz-0.8.1_1, /boot/efi/EFI/void/initramfs-0.8.1_1.img
Download pre-built binaries

mkdir -p /boot/efi/EFI/void
cd /boot/efi/EFI/void
curl -LJO https://get.zfsbootmenu.org/efi

Install and Configure rEFInd (optional)

rEFInd provides a convenient way to dynamically choose between multiple operating systems or, for recovery, prior versions of ZFSBootMenu images. It is also possible to create and directly boot a bundled UEFI executable for ZFSBootMenu.

rEFInd should automatically identify /boot/efi as your EFI partition and install itself accordingly.

xbps-install refind
refind-install
rm /boot/refind_linux.conf

Create /boot/efi/EFI/void/refind_linux.conf:

cat << EOF > /boot/efi/EFI/void/refind_linux.conf
"Boot default"  "zbm.prefer=zroot ro quiet loglevel=0 zbm.skip"
"Boot to menu"  "zbm.prefer=zroot ro quiet loglevel=0 zbm.show"
EOF

Exit the chroot, unmount everything

exit
umount -n /mnt/{dev/pts,dev,sys,proc}
umount /mnt/boot/efi

Export the zpool and reboot

zpool export zroot
reboot