Void Linux installation (on NVMe with trim enabled, with BTRFS filesystem, with Full Disk Encryption using LUKS, with swapfile)
This gist could be outdated, so if you prefer an automated script based on this gist, check out my github repo VoidLinuxInstaller!
This guide explains how to set up Void Linux:
- On an NVMe disk, enabling trim;
- Using Full Disk Encryption including
/boot
, with LUKS; - Using LVM for easy space management;
- Using btrfs as filesystem;
- Using a swapfile enabling also zswap; a swapfile is needed if you plan to use hibernation.
- SSD/NVMe trimming only works if it is enabled on all intermediate layers, which in this case means LUKS and btrfs
Username: root
Password: voidlinux
Load preferred keyboard layout:
loadkeys <kblayout>
Connecting to wifi (optional if already connected via ethernet cable):
ln -s /etc/sv/wpa_supplicant /var/service/
cp /etc/wpa_supplicant/wpa_supplicant.conf /etc/wpa_supplicant/wpa_supplicant-<interface>.conf
wpa_passphrase <SSID> <password> >> /etc/wpa_supplicant/wpa_supplicant-<interface>.conf
wpa_supplicant -B -i <interface> -c /etc/wpa_supplicant/wpa_supplicant-<interface>.conf
Be sure that efivars
are mounted if you are following this on an UEFI system:
mount -t efivarfs efivarfs /sys/firmware/efi/efivars
Partitioning the drive with cfdisk
with the the following scheme (using a 1 TB drive):
- 1 GB
/boot/efi
partition - 999 GB
/
partition
Encrypt the drive with LUKS1 because grub LUKS2 support is still limited:
cryptsetup luksFormat --type=luks1 /dev/nvme0n1p2
cryptsetup open /dev/nvme0n1p2 LinuxCrypt
Prepare LVM:
vgcreate LinuxGroup /dev/mapper/LinuxCrypt
lvcreate --name LinuxSystem -l +100%FREE LinuxGroup
Create filesystems:
mkfs.vfat -n EFIBOOT -F 32 /dev/nvme0n1p1
mkfs.btrfs -L VoidLinux /dev/mapper/LinuxGroup-LinuxSystem
Mount partitions and create btrfs subvolumes:
export BTRFS_OPT=rw,noatime,discard=async,compress-force=zstd,space_cache=v2,commit=120
mount -o $BTRFS_OPT /dev/mapper/LinuxGroup-LinuxSystem /mnt
btrfs subvolume create /mnt/@
btrfs subvolume create /mnt/@home
btrfs subvolume create /mnt/@snapshots
umount /mnt
mount -o $BTRFS_OPT,subvol=@ /dev/mapper/LinuxGroup-LinuxSystem /mnt
mkdir /mnt/home
mkdir /mnt/.snapshots
mount -o $BTRFS_OPT,subvol=@home /dev/mapper/LinuxGroup-LinuxSystem /mnt/home/
mount -o $BTRFS_OPT,subvol=@snapshots /dev/mapper/LinuxGroup-LinuxSystem /mnt/.snapshots/
mkdir -p /mnt/boot/efi
mount -o rw,noatime /dev/nvme0n1p1 /mnt/boot/efi/
mkdir -p /mnt/var/cache
btrfs subvolume create /mnt/var/cache/xbps
btrfs subvolume create /mnt/var/tmp
btrfs subvolume create /mnt/var/log
Install base system and chroot into it:
# If you want to install a musl system use these variables instead:
# export ARCH=x86_64-musl
# export REPO=https://repo-default.voidlinux.org/current/musl
export ARCH=x86_64
export REPO=https://repo-default.voidlinux.org/current
XBPS_ARCH=$ARCH xbps-install -Sy -r /mnt -R "$REPO" base-system btrfs-progs cryptsetup lvm2 grub-x86_64-efi grub-btrfs grub-btrfs-runit NetworkManager bash-completion nano wget gcc
for dir in sys dev proc; do mount --rbind /$dir /mnt/$dir; mount --make-rslave /mnt/$dir; done
cp -L /etc/resolv.conf /mnt/etc/
cp -L /etc/wpa_supplicant/wpa_supplicant-<interface>.conf /mnt/etc/wpa_supplicant/
BTRFS_OPTS=$BTRFS_OPTS PS1='(chroot) # ' chroot /mnt/ /bin/bash
Be sure that efivars
are mounted also inside chroot if you are running this script on an UEFI system:
mount -t efivarfs efivarfs /sys/firmware/efi/efivars
Set a new root password and set proper folder permissions:
passwd root
chown root:root /
chmod 755 /
Set a proper hoastname and edit rc files according to official documentation:
echo <hostname> > /etc/hostname
nano /etc/rc.conf
Set proper locale(s) uncommenting the right line(s) in /etc/default/libc-locales
.
Then add the same line(s) in /etc/locale.conf
:
echo LANG=en_US.UTF-8 > /etc/locale.conf
Edit /etc/fstab
file:
export UEFI_UUID=$(blkid -s UUID -o value /dev/nvme0n1p1)
export LUKS_UUID=$(blkid -s UUID -o value /dev/nvme0n1p2)
export ROOT_UUID=$(blkid -s UUID -o value /dev/mapper/LinuxGroup-LinuxSystem)
sed -i '/tmpfs/d' /etc/fstab
cat << EOF >> /etc/fstab
UUID=$ROOT_UUID / btrfs $BTRFS_OPT,subvol=@ 0 1
UUID=$ROOT_UUID /home btrfs $BTRFS_OPT,subvol=@home 0 2
UUID=$ROOT_UUID /.snapshots btrfs $BTRFS_OPT,subvol=@snapshots 0 2
UUID=$UEFI_UUID /boot/efi vfat defaults,noatime 0 2
tmpfs /tmp tmpfs defaults,noatime,mode=1777 0 0
EOF
Enable cryptodisk in /etc/default/grub
:
cat << EOF >> /etc/default/grub
GRUB_ENABLE_CRYPTODISK=y
EOF
sed -i "/GRUB_CMDLINE_LINUX_DEFAULT=/s/\"$/ rd.auto=1 rd.luks.name=$LUKS_UUID=LinuxCrypt rd.luks.allow-discards=$LUKS_UUID&/" /etc/default/grub
Generate random key to automatically decrypt LUKS drive after boot; this way you don't have to enter password twice every time:
dd bs=512 count=4 if=/dev/random of=/boot/volume.key
cryptsetup luksAddKey /dev/nvme0n1p2 /boot/volume.key
chmod 000 /boot/volume.key
chmod -R g-rwx,o-rwx /boot
cat << EOF >> /etc/crypttab
LinuxCrypt UUID=$LUKS_UUID /boot/volume.key luks
EOF
Use hostonly
for dracut; doing so dracut will generate a lean initramfs with everything needed:
echo -e "hostonly=yes\nhostonly_cmdline=yes" >> /etc/dracut.conf.d/00-hostonly.conf
echo "install_items+=\" /boot/volume.key /etc/crypttab \"" >> /etc/dracut.conf.d/10-crypt.conf
echo "add_dracutmodules+=\" crypt btrfs lvm resume \"" >> /etc/dracut.conf.d/20-addmodules.conf
echo "tmpdir=/tmp" >> /etc/dracut.conf.d/30-tmpfs.conf
dracut --regenerate-all --force --hostonly
If you want, you can also set up a swapfile in a btrfs subvolume. For that a file must be downloaded to compute the physical offset needed to compute the resume offset
.
The following instruction are for a system with 16GB or RAM. If you want a bigger swapfile change the value count=16
to the desired value:
btrfs subvolume create /var/swap
truncate -s 0 /var/swap/swapfile
chattr +C /var/swap/swapfile
chmod 600 /var/swap/swapfile
dd if=/dev/zero of=/var/swap/swapfile bs=1G count=16 status=progress
mkswap /var/swap/swapfile
swapon /var/swap/swapfile
wget https://raw.githubusercontent.com/osandov/osandov-linux/master/scripts/btrfs_map_physical.c
gcc -O2 btrfs_map_physical.c -o btrfs_map_physical
RESUME_OFFSET=$(($(./btrfs_map_physical /var/swap/swapfile | awk -F " " 'FNR == 2 {print $NF}')/$(getconf PAGESIZE)))
sed -i "/GRUB_CMDLINE_LINUX_DEFAULT=/s/\"$/ resume=UUID=$ROOT_UUID resume_offset=$RESUME_OFFSET&/" /etc/default/grub
cat << EOF >> /etc/fstab
/var/swap/swapfile none swap defaults 0 0
EOF
You can also consider enabling zswap that will use RAM as a cache for swapfile:
echo "add_drivers+=\" lz4hc lz4hc_compress z3fold \"" >> /etc/dracut.conf.d/40-add_zswap_drivers.conf
dracut --regenerate-all --force --hostonly
sed -i "/GRUB_CMDLINE_LINUX_DEFAULT=/s/\"$/ zswap.enabled=1 zswap.max_pool_percent=25 zswap.compressor=lz4hc zswap.zpool=z3fold&/" /etc/default/grub
update-grub
Install grub:
grub-install --target=x86_64-efi --boot-directory=/boot --efi-directory=/boot/efi --bootloader-id=VoidLinux --recheck
Enable internet at first boot:
ln -s /etc/sv/dhcpcd /etc/runit/runsvdir/default/
ln -s /etc/sv/wpa_supplicant/ /etc/runit/runsvdir/default/
Reconfigure every package:
xbps-reconfigure -fa
In case anything will break, you will just have to delete the @
subvolume, create it again and reinstall your distro. /home
folder won't be affected in any way.
In details, after booting a LiveCD, mount the encrypted partition:
cryptsetup open /dev/nvme0n1p2 LinuxCrypt
Scan for Volume Groups and then enable the one you need:
vgscan
vgchange -ay LinuxGroup
Mount the true btrfs root by its subvol
or by its subvolid
:
# by subvol
mount -o subvol=/ /dev/mapper/LinuxGroup-LinuxSystem /mnt
# or by subvolid
mount -o subvolid=0 /dev/mapper/LinuxGroup-LinuxSystem /mnt
After that if you do an ls /mnt/
you will see all the subvolume previously created.
Now you must delete ONLY the @
subvolume and finally unmount /mnt
btrfs subvolume delete /mnt/@
umount /mnt
At this point you can start again from Mount partitions and create btrfs subvolumes, without creating the @home
subvolume.
When the package reconfiguration is finished, you have to create a user with the same name of the one you created before, possibly adding it to the same groups as before, but you can do it later too.
Don't add the -m
flag or your original home folder will be destroyed:
useradd -G wheel <same_user>
passwd <same_user>
This is not necessary because adding the same user will automatically change the home folder permission, but just in case:
chown -R <same_user>:<same_user> /home/<same_user>
Probably the following could also be done from a running system, but maybe it's better to boot a LiveCD just in case. First a new physical drive must be added to the system. This drive in the following example will be called
/dev/sda
.
After booting a LiveCD, mount the encrypted partition:
cryptsetup open /dev/nvme0n1p2 LinuxCrypt
Scan for Volume Groups and then enable the one you need:
vgscan
vgchange -ay LinuxGroup
Scan for Logical Volumes and then enable the one you need:
lvscan
lvchange -ay LinuxGroup/LinuxSystem
Then a new Physical Volume for the new drive must be created:
pvcreate /dev/sda
After that it must be added to the existing Logical Volume:
vgextend LinuxSystem /dev/sda
Then the Logical Volume must be extended to cover the new free space:
lvm lvextend -l +100%FREE LinuxGroup/LinuxSystem
Finally also the BTRFS filesystem must be extended to cover all the free space; to do that, the BTRFS partition must be mounted:
mount -t btrfs /dev/mapper/LinuxGroup-LinuxSystem /mnt/
btrfs filesystem resize max /mnt/
- To speed up decryption at boot you could lower the number of iteration for each key as described on the Arch Wiki, but keep in mind that this comes with its own security concerns.
- I DON'T RECOMMEND FOLLOWING THIS, IT'S HERE ONLY AS REFERENCE:
[1] https://gist.github.com/tobi-wan-kenobi/bff3af81eac27e210e1dc88ba660596e
[2] https://gist.github.com/gbrlsnchs/9c9dc55cd0beb26e141ee3ea59f26e21