8bit avatar


It's in that place where I put that thing that time

7 min | linux

Encrypted Void Linux musl install via CLI

Pixelated scene from the movie Hackers with Nikon, Dade, Kate and Cereal staring at the screen

Looking for a lightweight linux distribution, not yet infected by systemd, that tries hard to follow the BSD philosophy?

The musl version of Void Linux is aimed exactly at that.

It’s on a rolling release schedule and uses both runit as its init system and libressl for cryptography straight from the OpenBSD project.

This is my step by step guide, that I’ve built over time and I constantly keep up to date, to install a minimal version of void linux via cli.

A few assumptions to make the process easier, we are going to:

  • Boot from uefi
  • Disable secure boot
  • Not encrypt the boot partition
  • Use a single partition (no root/home separation)
  • Use a swap file instead of a partition

If reading the above makes you concerned about security threats such as the evil maid attack you should definitely go for full disk encryption with detached headers, so this is clearly not the guide for you.

Before we get started head over to the void linux download page and get hold of the x64 musl iso image. With the iso downloaded we can write it to a usb stick using the dd command on linux or mac (if you are on windows you can use a tool like unetbootin).

# make sure to replace sdX with the correct
# device as dd is not a forgiving command
# you can use the lsblk command to find it
sudo dd bs=4M if=void-live-x86_64-musl-20191109.iso of=/dev/sdX

Now make sure your bios is set to use uefi and boot your machine from the usb drive you just created. You should be greeted by a login screen where you can enter root as the username and voidlinux as the password to get in.

This is the void linux live environment (running entirely from ram) from which we will perform the installation.

We can start by jumping into bash (as the live image uses the sh shell) and setting the keyboard layout.

loadkeys uk

If you are planning to use wifi, connect using the wpa supplicant and then get a lease via the dhcp client.

# replace the interface ssid and psw
wpa_supplicant -B -i wlp4s0 -c <(wpa_passphrase ssid psw)
dhcpcd wlp4s0

If you are on a wired connection, find your ethernet interface and use the dhcp client to obtain a lease.

dhcpcd enp0s31f6

Time to check our connection by issuing the ping command.

ping -c 3

We are now ready to wipe the internal disk and create the new partitions on a gpt schema.

# replace nvme0n1 with your internal disk device

# we discard the ssd content first
blkdiscard /dev/nvme0n1

# then use fdisk to partition
fdisk /dev/nvme0n1
# create a blank gpt schema
# create the boot partition
# default the first sector
# enter the size of the last sector
# change partition type
# set it to efi
# create another partition (we will encrypt this later on)
# default everything
# write the changes to disk

Time to create our encrypted luks container on the second partition, this will hold our rootfs.

# replace nvme0n1p2 with your second partition
cryptsetup \
    --cipher aes-xts-plain64 \
    --key-size 512 \
    --hash sha512 \
    --iter-time 5000 \
    --use-random \
    luksFormat /dev/nvme0n1p2

We should now decrypt our luks container to prep its inside.

# replace nvme0n1p2 with your second partition
cryptsetup luksOpen /dev/nvme0n1p2 crypto

Time to create the filesystems, we are going to use FAT32 for the boot partition (as it’s required by the uefi boot) and btrfs on top of the luks container.

# replace nvme0n1p1 with your boot partition
mkfs.fat -F 32 /dev/nvme0n1p1
mkfs.btrfs -L rootfs /dev/mapper/crypto

The disk is now ready, we shoud mount the volumes and do some cleanup.

mount /dev/mapper/crypto /mnt
mkdir /mnt/boot
# replace nvme0n1p1 with your boot partition
mount /dev/nvme0n1p1 /mnt/boot

As we are installing the musl variant of void linux we will need to export an environmental variable to tip the package manager (xbps) of the intended architecture.

export XBPS_ARCH=x86_64-musl

We can now install the base system and few additional packages, grub (the bootloader) and cryptsetup (to manage the encrypted volume).

xbps-install -Sy \
    --repository=https://alpha.de.repo.voidlinux.org/current/musl \
    --rootdir /mnt \
    base-system \
    cryptsetup \

One last step, before we enter our newly installed system, is to mount some folders from the host that will be used by grub later on.

mount -t proc /proc /mnt/proc
mount --rbind /dev /mnt/dev
mount --rbind /sys /mnt/sys

We can now chroot into the new installation and change both the default shell and root password.

chroot /mnt /bin/bash

# change the default shell to bash
chsh -s /bin/bash

# change the root password

Instead of using a swap partition we are going to take advantage of a swap file, this way we can resize and relocate it however we see fit. As we are using btrfs we need to disable cow (copy on write) and compression before we can enable swap using the swapfile.

# create a zero length file
truncate -s 0 /swapfile

# disable cow
chattr +C /swapfile

# disable compression
btrfs property set /swapfile compression none

# allocate the size
fallocate -l 24g /swapfile

# lock down permissions
chmod 600 /swapfile

# make it swappable
mkswap /swapfile

Time to create a new user and assign it to some of the groups, feel free to add or remove groups here depending on your requirements. Just note that the wheel group is used in the last step to allow sudo access to our newly created user.

# replace zerocool with your user handle
useradd \
    --create-home \
    --groups wheel,users,audio,video,storage,cdrom,input \
    --shell /bin/bash \

# change the password
passwd zerocool

# fire the visudo command
# and uncomment the following line
# to allow sudo access to
# users in the wheel group
%wheel ALL=(ALL) ALL

Now we can set some defaults to handle the timezone and keymap at boot. We should also set the correct language for our locale.

# tweak the following lines in /etc/rc.conf

# tweak the language for your locale in /etc/locale.conf

We need to set the hostname in two places.

# add the hostname to /etc/hostname
# replace gibson with your hostname
echo gibson > /etc/hostname

# tweak the /etc/hosts to include your hostname
# also replace gibson here with your hostname gibson.lan gibson localhost.localdomain localhost
::1 gibson.lan gibson localhost.localdomain localhost ip6-localhost

Our next step is to populate the fstab with the boot volume and the swap file.

# add the following lines to your /etc/fstab

# replace nvme0n1p1 with your boot partition
/dev/nvme0n1p1 /boot vfat rw,noatime,discard 0 2

/swapfile none swap defaults 0 0

As we are going to use dracut to generate the initramfs image to boostrap the kernel we need to add an override to install only what is needed to boot the localhost.

# create a new file in /etc/dracut.conf.d/override.conf
# containing the following line

Now we can tweak the grub default config to disable timeout and enable the autoassembly of special devices, in our case the luks volume, don’t forget to add the discard option if you are using an ssd.

# edit the following lines in /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="loglevel=4 rd.auto=1 rd.luks.allow-discards"

Time to install the bootloader.

# install grub
grub-install \
    --target=x86_64-efi \

# generate grub config
grub-mkconfig -o /boot/grub/grub.cfg

Last step is to generate the initramfs image using dracut.

# replace 5.8 with the correct version
# you can find it in the output
# of the grub command above
xbps-reconfigure -f linux5.8

All done, we are now ready to reboot into void linux.

# exit the chroot

# unmount recursively from /mnt
umount -R /mnt


Now that our base install is complete we can go ahead and setup xorg and i3wm.