Skip to content

Instantly share code, notes, and snippets.

@gbrlsnchs
Last active January 29, 2024 00:10
Show Gist options
  • Star 51 You must be signed in to star a gist
  • Fork 17 You must be signed in to fork a gist
  • Save gbrlsnchs/9c9dc55cd0beb26e141ee3ea59f26e21 to your computer and use it in GitHub Desktop.
Save gbrlsnchs/9c9dc55cd0beb26e141ee3ea59f26e21 to your computer and use it in GitHub Desktop.
Void Linux Installation Guide (UEFI + chroot + brtfs + LUKS-encrypted root and swapfile)

Installation guide for Void Linux with LUKS-encrypted btrfs root

NOTE

I have ported this Gist to a handbook. I'll not maintain this Gist anymore, but will keep it here for future references. You can access the respective chapter in the handbook here.

Introduction

In this guide you will find:

  • btrfs with Zstandard compression
  • LUKS-encrypted root and swapfile
  • GRUB with UEFI

You will not find:

  • Instructions for file systems other than btrfs
  • Full disk encryption (there's an official guide here)
  • Explanation for all choices I've made (sometimes I don't know the true reason behind my choices)

Index

  1. Setting up the live ISO
    1. Logging in
    2. Configuring the keyboard layout
    3. Connecting to the internet
  2. Formatting disks
    1. Partitioning
    2. Creating the file systems
      1. EFI partition
      2. Boot partition
      3. LUKS-encrypted root partition
    3. Mounting partitions
      1. Root partition
      2. EFI and boot partitions
  3. Installing the system
    1. Base installation
    2. Running chroot
    3. Basic configuration
      1. Hostname
      2. System configuration information
      3. Configuring locales
      4. Root password
      5. Configuring fstab
      6. Setting up Dracut
    4. Finishing installation
      1. Intel microcode
      2. GRUB
      3. Swapfile
      4. Regenerating configurations
  4. Post-installation
    1. Creating the main user
    2. Session management

Setting up the live ISO

Logging in

There are two available users, root (superuser) and anon. The password of both is voidlinux. I like to log in using the superuser so I don't have to type sudo at all. I highly suggest you run exec bash so you don't have to deal with dash's limitations.

Configuring the keyboard layout

If you need a different layout other than en-US, you can do the following:

# loadkeys $(ls /usr/share/kbd/keymaps/i386/**/*.map.gz | grep <your-layout>)

Connecting to the internet

# cp /etc/wpa_supplicant/wpa_supplicant.conf /etc/wpa_supplicant/wpa_supplicant-<wlan-interface>.conf
# wpa_passphrase <ssid> <passphrase> >> /etc/wpa_supplicant/wpa_supplicant-<wlan-interface>.conf
# sv restart dhcpcd
# ip link set up <interface>

Formatting disks

Partitioning

The minimum number of partitions is three:

  • The EFI partition (/efi)
  • The boot partition, where kernels are stored (/boot)
  • The LUKS-encrypted btrfs root partition

So, first we need to generate the partition tables. Check which device is the one you want to install Void into. For this guide I'll simply use /dev/sda, but it can change depending on your setup, so watch out! Back to the partition tables:

# fdisk /dev/sda

After running fdisk, it will prompt you with a menu, so follow these steps:

  1. Select g to generate a GTP table
  2. Select n to create the EFI partition with size of +200M
  3. After creating the partition, change its type by selecting t and then selecting the option that represents EFI Partition (generally 1)
  4. Select n to create the boot partition with size of +500M (more space means more kernels, I like using +800M)
  5. Select n to create the btrfs partition with the remaining size

Creating the file systems

EFI partition

# mkfs.vfat -nBOOT -F32 /dev/sda1

Boot partition

# mkfs.ext2 -L grub /dev/sda2

LUKS-encrypted root partition

# cryptsetup luksFormat --type=luks -s=512 /dev/sda3
# cryptsetup open /dev/sda3 cryptroot
# mkfs.btrfs -L void /dev/mapper/cryptroot

Mounting partitions

Root partition

First, let's mount the main btrfs partition:

# BTRFS_OPTS="rw,noatime,ssd,compress=zstd,space_cache,commit=120"
# mount -o $BTRFS_OPTS /dev/mapper/cryptroot /mnt
# btrfs subvolume create /mnt/@
# btrfs subvolume create /mnt/@home
# btrfs subvolume create /mnt/@snapshots
# umount /mnt

Then, let's mount the top-level partitions:

/
# mount -o $BTRFS_OPTS,subvol=@ /dev/mapper/cryptroot /mnt
/home
# mkdir -p /mnt/home
# mount -o $BTRFS_OPTS,subvol=@home /dev/mapper/cryptroot /mnt/home
/.snapshots
# mkdir -p /mnt/.snapshots
# mount -o $BTRFS_OPTS,subvol=@snapshots /dev/mapper/cryptroot /mnt/.snapshots

NOTE: Configure mount options according to your needs.

After that, let's mount some nested partitions, which won't have a snapshot taken, since snapshots don't work resursively:

# mkdir -p /mnt/var/cache
# btrfs subvolume create /mnt/var/cache/xbps
# btrfs subvolume create /mnt/var/tmp
# btrfs subvolume create /mnt/srv

You also need to create a nested subvolume for the swapfile:

# btrfs subvolume create /mnt/var/swap

EFI and boot partitions

Once the root partition is mounted, it is time to mount the remaining ones:

/efi
# mkdir /mnt/efi
# mount -o rw,noatime /dev/sda1 /mnt/efi
/boot
# mkdir /mnt/boot
# mount -o rw,noatime /dev/sda2 /mnt/boot

Installing the system

Base installation

Set the appropriate variables (this may vary depending on your needs):

# REPO=https://alpha.us.repo.voidlinux.org/current
# ARCH=x86_64

If using musl, the values might be something like:

# REPO=https://alpha.us.repo.voidlinux.org/current/musl
# ARCH=x86_64-musl

NOTE: Here is a handful of mirrors.

Then run:

XBPS_ARCH=$ARCH xbps-install -S -R "$REPO" -r /mnt base-system btrfs-progs cryptsetup

The command above installs the base system along with btrfs utilites, GRUB and dm-crypt utility, which are core parts of this setup.

Running chroot

Mount the pseudo file systems needed for a chroot:

# for dir in dev proc sys run; do mount --rbind /$dir /mnt/$dir; mount --make-rslave /mnt/$dir; done

Copy the DNS configuration into the new root so that XBPS can still download new packages inside the chroot:

# cp /etc/resolv.conf /mnt/etc/

Then chroot into the new installation:

# BTRFS_OPTS=$BTRFS_OPTS PS1='(chroot) # ' chroot /mnt/ /bin/bash

Basic configuration

Hostname

Write the desired hostname to /etc/hostname.

System configuration information

Refer to this documentation in order to configure your rc.conf file.

Configuring locales

For glibc installations, edit /etc/default/libc-locales, then run:

(chroot) # xbps-reconfigure -f glibc-locales

Root password

(chroot) # passwd

Configuring fstab

(chroot) # UEFI_UUID=$(blkid -s UUID -o value /dev/sda1)
(chroot) # GRUB_UUID=$(blkid -s UUID -o value /dev/sda2)
(chroot) # ROOT_UUID=$(blkid -s UUID -o value /dev/mapper/cryptroot)
(chroot) #  cat <<EOF > /etc/fstab
UUID=$ROOT_UUID / btrfs $BTRFS_OPTS,subvol=@ 0 1
UUID=$UEFI_UUID /efi vfat defaults,noatime 0 2
UUID=$GRUB_UUID /boot ext2 defaults,noatime 0 2
UUID=$ROOT_UUID /home btrfs $BTRFS_OPTS,subvol=@home 0 2
UUID=$ROOT_UUID /.snapshots btrfs $BTRFS_OPTS,subvol=@snapshots 0 2
tmpfs /tmp tmpfs defaults,nosuid,nodev 0 0
EOF

Setting up Dracut

I advise doing a "hostonly" install, that is, Dracut will generate a lean initramfs with everything you might need, including i915 drivers if you have an Intel CPU with integrated graphics:

(chroot) # echo hostonly=yes >> /etc/dracut.conf

Finishing installation

Intel microcode

(chroot) # xbps-install -Su void-repo-nonfree intel-ucode

GRUB

(chroot) # xbps-install grub-x86_64-efi
(chroot) # grub-install --target=x86_64-efi --efi-directory=/efi --bootloader-id="Void Linux"

Swapfile

In order to have an encrypted swap, let's use a more modern approach by using a swapfile as our swap partition. For this example, I'll create a swapfile of 16 GiB, but you can choose the best size for your installation:

(chroot) # btrfs subvolume create /var/swap
(chroot) # truncate -s 0 /var/swap/swapfile
(chroot) # chattr +C /var/swap/swapfile
(chroot) # btrfs property set /var/swap/swapfile compression none
(chroot) # chmod 600 /var/swap/swapfile
(chroot) # dd if=/dev/zero of=/var/swap/swapfile bs=1G count=16 status=progress
(chroot) # mkswap /var/swap/swapfile
(chroot) # swapon /var/swap/swapfile

After that, follow this Arch's guide on calculating the resume_offset kernel parameter for btrfs.

HINT: You can use XBPS to compile the btrfs_map_physical for you by using my own template. Just clone the branch and use xbps-src as usual to pkg the btrfs_map_physical package.

After calculating it, append the following line to GRUB's config:

(chroot) # RESUME_OFFSET=<calculated-offset-from-tutorial-above>
(chroot) # cat <<EOF >> /etc/default/grub
GRUB_CMDLINE_LINUX="resume=UUID=$ROOT_UUID resume_offset=$RESUME_OFFSET"
EOF

NOTE: You need Linux 5.0+ in order to use a swapfile with btrfs.

Regenerating configurations

(chroot) # xbps-reconfigure -fa
(chroot) # exit
# shutdown -r now

Post-installation

Creating the main user

Log in as root and then run:

# xbps-install -S zsh
# useradd -m -G wheel,input,video -s /bin/zsh <username>
# passwd <username>
# visudo

After running visudo, uncomment the line that contains %wheel. Log out and then log in with the newly created user.

NOTE: If you want to lock down the root account, you can run sudo passwd -dl root. Be careful though, since you won't be able to log in using the root account anymore.

Session management

Please refer to this official guide from the handbook.

@zelleb
Copy link

zelleb commented Mar 8, 2020

Great guide! But what are those nested partitions for? Are they mounted automatically? You didn't add them to /etc/fstab.

@gbrlsnchs
Copy link
Author

Great guide!

Thanks! It still needs some polish but might be a starting point for folks out there.

But what are those nested partitions for?

In btrfs, snapshots don't work recursively. You have to take a snapshot of each individual existing subvolume. That allows us to exclude those "nested partitions" from snapshots.

Are they mounted automatically? You didn't add them to /etc/fstab.

Yes, here is a quote from btrfs' wiki:

Subvolumes can be nested and each subvolume (except the top-level subvolume) has a parent subvolume. Mounting a subvolume also makes any of its nested child subvolumes available at their respective location relative to the mount-point.

In other words, you only need to mount top-level subvolumes and their child subvolumes will get mounted along with them.

Have fun with Void! 🐱

@zelleb
Copy link

zelleb commented Mar 8, 2020

OK, so those 3 nested partitions are children of /@, are mounted with it and excluded from snapshots of /@. Cool.

I did a few trail and error installs on a separate drive with efibootmgr. Finally got it working and was unsure about the nested partitions. Gonna wipe my main drive and jump into the void now!

Thanks.

@gbrlsnchs
Copy link
Author

OK, so those 3 nested partitions are children of /@, are mounted with it and excluded from snapshots of /@. Cool.

Exactly!

I did a few trail and error installs on a separate drive with efibootmgr. Finally got it working and was unsure about the nested partitions. Gonna wipe my main drive and jump into the void now!

Thanks.

Cool, welcome and have fun with it! 😸

@tobi-wan-kenobi
Copy link

Thanks a lot for this guide, it was such a help when entering the Void!

A few small remarks:

  • Instead of restarting dhcpcd, I had to manually start wpa_supplicant: wpa_supplicant -B -i <interface> -c <configuration>
  • Setting the shell via which zsh broke login for me (since which zsh points to /usr/bin/zsh, but for setting the shell, only /bin/zsh works for me.
  • For convenience, it might be good to copy the wpa_supplicant-.conf into the chroot

Thanks again!

@gbrlsnchs
Copy link
Author

Thanks a lot for this guide, it was such a help when entering the Void!

Glad I could help! One day I'll tidy and polish this tutorial.

  • Instead of restarting dhcpcd, I had to manually start wpa_supplicant: wpa_supplicant -B -i <interface> -c <configuration>

My Void Live image already had wpa_supplicant spinning as a service, so I'm not sure why it wasn't the same for you. 😿

  • Setting the shell via which zsh broke login for me (since which zsh points to /usr/bin/zsh, but for setting the shell, only /bin/zsh works for me.

Yeah, you're right, it's better to not use which zsh, which sometimes points to undesired places.

  • For convenience, it might be good to copy the wpa_supplicant-.conf into the chroot

Personally, everytime I installed Void, I logged as root. It's much easier as no sudo nor doas is required.

Thanks again!

No problem, I hope you have fun, Void is awesome!

Copy link

ghost commented Mar 26, 2020

I do not think the grub partition is strictly necessary. Grub can be installed to the ESP, its just that void's automatic installer (for whatever reason) requires the ESP to be mounted at /boot/efi/, which would normally put grub inside of your encrypted root.

But since you are installing grub manually, this shouldn't be an issue. I think the rationale is that at some point, this allowed you to update the kernel without mounting your ESP, but I think that updating the kernel with xbps ends up running grub, mounting the ESP and regenerating the efi image anyhow.

@jelemux
Copy link

jelemux commented Apr 14, 2020

Thank you very much for this guide! It put me on a great journey.
I now have PTSD from the dracut rescue shell but that was worth it!

However, I had to do a few things differently to get everything to work.

First it said it couldn't find the UUID of my encrypted drive, so I found out that it didn't decrypt it.
So I put this line into my /etc/default/grub (I found that in the Arch Wiki Article about dm-crypt):

GRUB_CMDLINE_LINUX="cryptdevice=UUID=9c20edda-4ee6-420c-8c61-5b34af6dc890:cryptroot root=/dev/mapper/cryptroot i915.modeset=1" 

and changed the entry in /etc/fstab to /dev/mapper/cryptroot instead of the UUID.

After that it decrypted my drive but couldn't mount it because it somehow was called /dev/mapper/luks-9c20edda-4ee6-420c-8c61-5b34af6dc890.
So figured if I changed the entry in my fstab I could get it to work. Changed the entry in /etc/default/grub too for consistency, and it worked!

The entry in /etc/default/grub as it looks now:

GRUB_CMDLINE_LINUX="cryptdevice=UUID=9c20edda-4ee6-420c-8c61-5b34af6dc890:luks-9c20edda-4ee6-420c-8c61-5b34af6dc890 root=/dev/mapper/luks-9c20edda-4ee6-420c-8c61-5b34af6dc890 i915.modeset=1"

And the entries for the encrypted drive in my fstab:

/dev/mapper/luks-9c20edda-4ee6-420c-8c61-5b34af6dc890 /           btrfs rw,noatime,ssd,compress=zstd,space_cache,commit=120,subvolid=257 0 1
/dev/mapper/luks-9c20edda-4ee6-420c-8c61-5b34af6dc890 /home       btrfs rw,noatime,ssd,compress=zstd,space_cache,commit=120,subvolid=258 0 2
/dev/mapper/luks-9c20edda-4ee6-420c-8c61-5b34af6dc890 /.snapshots btrfs rw,noatime,ssd,compress=zstd,space_cache,commit=120,subvolid=259 0 2

If I did anything wrong please point me to it, otherwise I hope that my experiences may help others.

Also, what wasn't fully clear to me (although I suspected it) is that I have to rerun the dracut command and grub-mkconfig for the new Kernel. So it's worth to point that out as well.
I was also thinking about the possibility to create some kind of hook to run those commands automatically. Is this possible and how would I go about doing that?

@gbrlsnchs
Copy link
Author

Also, what wasn't fully clear to me (although I suspected it) is that I have to rerun the dracut command and grub-mkconfig for the new Kernel. So it's worth to point that out as well.
I was also thinking about the possibility to create some kind of hook to run those commands automatically. Is this possible and how would I go about doing that?

I think if you run xbps-reconfigure -f <linux-pkg>, it will force triggering a hook for Linux package and both Dracut and GRUB will be reconfigured.

@Ingvix
Copy link

Ingvix commented Jul 2, 2020

Could you give some extra instructions on migrating existing system to encrypted one? I feel a bit frustrated to my know-how being so limited and would like to have some clear steps on how to do this.

I currently have more than half of the disk space free so I assume I don't need another disk to do this, though I do have one available. I have a quite basic installation of separated root and home partitions with ext4 fs's on GPT table and with efi boot. Also grub.

@Kratacoa
Copy link

Kratacoa commented Jul 4, 2020

I am not the author, but I think I might be able to reply;

Could you give some extra instructions on migrating existing system to encrypted one? I feel a bit frustrated to my know-how being so limited and would like to have some clear steps on how to do this.

luksFormat command required to create a LUKS container formats the device, so it's probably not possible to do a migration without backing up beforehand; besides, not wiping the dreave correctly leaves a lot of data from the previous installation unencrypted until it gets overwritten.

@gbrlsnchs
Copy link
Author

gbrlsnchs commented Aug 24, 2020

I do not think the grub partition is strictly necessary. Grub can be installed to the ESP, its just that void's automatic installer (for whatever reason) requires the ESP to be mounted at /boot/efi/, which would normally put grub inside of your encrypted root.

But since you are installing grub manually, this shouldn't be an issue. I think the rationale is that at some point, this allowed you to update the kernel without mounting your ESP, but I think that updating the kernel with xbps ends up running grub, mounting the ESP and regenerating the efi image anyhow.

Thanks for the info. So you're saying I could mount the ESP to /efi and also install GRUB there? How would it read the kernel from the encrypted /boot directory?

Copy link

ghost commented Oct 1, 2020

you also need chmod 755 /home directory on btrfs if you dont want to see this when create new user

change directory failed : Permission denied

and here is a working grub (MBR+BTRFS)

GRUB_CMD_LINUX="cryptdevice=UUID="":lvm rd.auto=1 rd.luks.allow-discards i915.modeset=1"

@ampersandcastles
Copy link

So this code has a typo:

(chroot) # ROOT_UUID=$(blkid -s UUID -o value /dev/mapper/cryptoroot)

You named it "cryptroot" earlier, but calling for cryptoroot here.

@gbrlsnchs
Copy link
Author

So this code has a typo:

(chroot) # ROOT_UUID=$(blkid -s UUID -o value /dev/mapper/cryptoroot)

You named it "cryptroot" earlier, but calling for cryptoroot here.

Oops, my bad. Thanks for the heads-up, fixed it!

@yamirror
Copy link

yamirror commented May 20, 2021

Hi there! Thanks a lot for the install-description! I was searching for that. Cause I want to try install multiboot distro/BSD... Right now only GNU Linux, without BSD's, on just one btrfs partion.
The idea is to try to install it on just on 1 partion (sda1) with dos-MBR part-table. Then create on sda1 subvolumes like void-root, void-home etc. After that another distro again on sda1, but with subvol like artix-root,artix-boot etc. And of cource a subvolume for swap & data
Now I'm just trying it. After install I can say more. But one I know, that os-prober doesn't find distributions on same partion & different subvolumes. So I need to config it manually. But there is another instruction how to config grub for multiboot on btrfs subvolumes))
So what I thought. If I create nested subvolumes like
#btrfs subvolume create /mnt/var/tmp

btrfs subvolume create /mnt/srv

You also need to create a nested subvolume for the swapfile:

btrfs subvolume create /mnt/var/swap

So when I install a second distro with the same subvolumes like /mnt/var/tmp. Would be there a conflict? Cause the subvolume-name would be /mnt/var/tmp on both distros? Or would it register like child from exactly subvol=void-root? And not like child from whole btrfs ssda1 partion?

I like the way with nested subvolumes more. But not sure wouldit be a conflict between 2 distros with same subvol-name. Then my idea would be create all subvols as subvolid=5, and give them different names like void-root, void-tmp, void-xbps etc.

@djorborn
Copy link

After finishing the install, getting everything in place and setting up timeshift, then some time goes by, I use timeshift restore. After that, xbps-install will not work. it says Permission denied, I have checked my date and time, and also did the whole thing over in a VM with the same results. Anyone else have this issue with timeshift with btrfs? Even going back to the most current time has the same issue. Have not been able to find a fix.

Error:

2021-12-20T14:15:09.79868 user.err: Dec 20 09:15:09 xbps-install: [trans] failed to download `libffi-3.3_2' signature from `https://alpha.de.repo.voidlinux.org/current': Permission denied

@mtroberts
Copy link

@djorborn - I appreciate it's been a while, but deleting /var/cache/xbps fixes issues after timeshift.

@Pixxler
Copy link

Pixxler commented Aug 21, 2022

IMG_20220821_185622_414
I am getting this issue every time i want to install

  • Grub- install : error: failed to get canonical path of '/efi'.

Tried 3 times. Same problem. Any solution please. Thanks in advance.

@gbrlsnchs
Copy link
Author

IMG_20220821_185622_414 I am getting this issue every time i want to install

* Grub- install : error: failed to get canonical path of '/efi'.

Tried 3 times. Same problem. Any solution please. Thanks in advance.

Do you have the EFI partition mounted on /efi? Sometimes it's on /boot/efi.

@EwolBash
Copy link

Thanks for the guide. It's way over my head, but I managed to get it mostly working.

The swap file doesn't seem activate unless I manually run

swapon /var/swap/swapfile

Each time after reboot. Did I go wrong somewhere in the guide?

Also in the latest void ISO space_cache prevents me from mounting. Removed it and never ran in to any issues.

@mtroberts
Copy link

Thanks for the guide. It's way over my head, but I managed to get it mostly working.

The swap file doesn't seem activate unless I manually run

swapon /var/swap/swapfile

Each time after reboot. Did I go wrong somewhere in the guide?

Also in the latest void ISO space_cache prevents me from mounting. Removed it and never ran in to any issues.

You need to use space_cache=v2

Check the arch wiki on swap. Is swap in your FSTAB?

@ElPresidentePoole
Copy link

The URL this gist links to seems to be down. Is there a new URL?

@gbrlsnchs
Copy link
Author

The URL this gist links to seems to be down. Is there a new URL?

It is now only in https://gbrlsnchs.github.io/handbook/, sorry for that.

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