Skip to content

Instantly share code, notes, and snippets.

@Le0xFF
Forked from tobi-wan-kenobi/VOID-INSTALL.md
Last active August 26, 2024 00:09
Show Gist options
  • Save Le0xFF/ff0e3670c06def675bb6920fe8dd64a3 to your computer and use it in GitHub Desktop.
Save Le0xFF/ff0e3670c06def675bb6920fe8dd64a3 to your computer and use it in GitHub Desktop.
Void Linux installation (on NVMe with trim enabled, with BTRFS filesystem, with Full Disk Encryption using LUKS, with swapfile)

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!


Features

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.

Important notes

  • SSD/NVMe trimming only works if it is enabled on all intermediate layers, which in this case means LUKS and btrfs

The process

Pre-chroot

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

Post-chroot

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

Follow-up for snapper issues


What if system breaks?

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>

How to add more space with a new drive with LVM

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/

Notes


References

[1] https://gist.github.com/tobi-wan-kenobi/bff3af81eac27e210e1dc88ba660596e

[2] https://gist.github.com/gbrlsnchs/9c9dc55cd0beb26e141ee3ea59f26e21

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