Convert GRUB to systemd-boot (EFI)

If you’ve followed my earlier guide on how to install Arch Linux you’ve probably used GRUB to boot the system. Now it’s time to step into the future even further with systemd-boot instead!

Run the command below to begin the installation, the path is your EFI-partition.

bootctl --path=/boot/efi install

Create the file /boot/efi/loader/entries/arch.conf with the following content, or as you have your partitions set up:
title   Arch Linux
linux   /vmlinuz-linux
initrd  /initramfs-linux.img
options cryptdevice=/dev/sda3:lvm root=/dev/mapper/lvmvg-rootvol rw rootflags=subvol=root resume=/dev/mapper/lvmvg-swapvol quiet

Edit the file /boot/efi/loader/loader.conf:
timeout 3
default arch

Copy all *.img files and vmlinuz-linux from /boot to /boot/efi folder

Create /etc/systemd/system/efistub-update.path with the following content:
[Unit]
Description=Copy EFISTUB Kernel to EFI System Partition
[Path]
PathChanged=/boot/initramfs-linux-fallback.img
[Install]
WantedBy=multi-user.target
WantedBy=system-update.target

Create /etc/systemd/system/efistub-update.service with the following content:
[Unit]
Description=Copy EFISTUB Kernel to EFI System Partition
[Service]
Type=oneshot
ExecStart=/usr/bin/cp -f /boot/vmlinuz-linux /boot/efi/vmlinuz-linux
ExecStart=/usr/bin/cp -f /boot/initramfs-linux.img /boot/efi/initramfs-linux.img
ExecStart=/usr/bin/cp -f /boot/initramfs-linux-fallback.img /boot/efi/initramfs-linux-fallback.img

Run the following commands:
systemctl enable efistub-update.path
systemctl start efistub-update.path

Reboot your system to see that it starts using systemd-boot instead of GRUB. If everything works you can remove GRUB and its’ files on the /boot-partition:
pacman -Rs grub
rm -r /boot/grub

Automatic snapshots with btrfs and ruby

I’ve been using this script for a while to automatically create snapshots of my system and rotate old snapshots. It has saved me a few times when an upgrade has gone wrong, or a setting crashed my whole desktop:

https://github.com/markmcb/btrfs_snapshot_rotate

It’s easy to set up, just install the packages below (on Arch Linux):
pacman -S ruby

the Ruby gem ‘colorize’ is also required (run as root or with sudo):
gem install colorize

After installing the packages you will need to add the btrfs-root to a mountpoint, I’m using /mnt/snapshots for this. Add this to your /etc/fstab if you’ve followed my earlier guide on how to set up Arch Linux:
/dev/mapper/lvmvg-rootvol /mnt/snapshots btrfs rw,relatime,noauto 0 0

Then you need to edit the script downloaded from markmcb’s github. Below is what I use on one of my machines:

SnapshotConfigurations = [
{
# array of mount points. Path must be in /etc/fstab with mount options.
# All mounts listed will be unmounted when the script completes.
# If everything is already mounted, leave an empty array, i.e, []
full_paths_to_mount: ['/mnt/snapshots'],
full_path_of_source_subvolume: '/mnt/snapshots/root',
full_path_of_snapshot_directory: '/mnt/snapshots',
snapshot_filename_prefix: 'root_snapshot',
# Define how many snapshots to keep in different time aggregations
keep: { days: 7, weeks: 4, day_of_week: "Monday", months: 2, years: 0 }
},
{
# array of mount points. Path must be in /etc/fstab with mount options.
# All mounts listed will be unmounted when the script completes.
# If everything is already mounted, leave an empty array, i.e, []
full_paths_to_mount: ['/mnt/snapshots'],
full_path_of_source_subvolume: '/mnt/snapshots/home',
full_path_of_snapshot_directory: '/mnt/snapshots',
snapshot_filename_prefix: 'home_snapshot',
# Define how many snapshots to keep in different time aggregations
keep: { days: 7, weeks: 4, day_of_week: "Monday", months: 2, years: 0 }
}
]

Before you can add cronjobs you must install a cron handler, I recommend cronie, install and activate it with:
pacman -S cronie
systemctl enable cronie

Lastly just add the script to your root’s crontab (with crontab -e):
0 23 * * * ruby /home/username/bin/btrfs_snapshot_rotate.rb -y

I would recommend running the command manually once to see that it works as well.

If disaster strikes and you need to restore a snapshot, you can use this cheatsheet to get started:
* Start Arch Linux boot USB/CD
* Mount your disk
loadkeys sv-latin1
cryptsetup luksOpen /dev/sda3 lvm
mount /dev/mapper/lvmvg-rootvol /mnt

* Go to /mnt and see which snapshots are available

If you want to, for example, restore your root to an earlier snapshot, you can do like this:
mv root root_
btrfs subvolume snapshot root_snapshot-2016-09-26 root

If you changed the kernel version between that snapshot and the live image (so that your /boot and /boot/efi was modified), you also need to mount those partitions and re-run the kernel-installation.
umount /mnt
mount -o subvol=root,ssd /dev/mapper/lvmvg-rootvol /mnt
mount -o subvol=home,ssd /dev/mapper/lvmvg-rootvol /mnt/home
swapon /dev/mapper/lvmvg-swapvol
mount /dev/sda2 /mnt/boot
mount /dev/sda1 /mnt/boot/efi
arch-chroot /mnt /bin/zsh
pacman -S linux

This should make your OS bootable again with the kernel found in the snapshot you restored!
If everything work, you can remove your broken root by mounting /mnt/snapshot, go into that folder, and run btrfs subvolume delete root_

Enable discard (TRIM) on SSDs while running LVM on LUKS and Btrfs (Arch)

You might’ve followed the guide at my guide on how to install Arch, and would like to enable the Discard command on your shiny SSD, to keep it fresh!

First add discard as a mount-option to your /etc/fstab:
/dev/mapper/lvmvg-rootvol / btrfs rw,relatime,ssd,discard,compress=lzo,space_cache,subvol=root 0 0
/dev/mapper/lvmvg-rootvol /home btrfs rw,relatime,ssd,discard,compress=lzo,space_cache,subvol=home 0 0

Then allow discard-command to go through LVM in /etc/lvm/lvm.conf:
...
issue_discards = 1
...

Then enable the fstrim.timer systemctl with:
systemctl enable fstrim.timer

And at last add it to your boot-section in /etc/default/grub:
GRUB_CMDLINE_LINUX="cryptdevice=/dev/sda3:lvm:allow-discards root=/dev/mapper/lvmvg-rootvol rootflags=subvol=root resume=/dev/mapper/lvmvg-swapvol"

Finally regenerate your grub with:
grub-mkconfig -o /boot/grub/grub.cfg

Reboot and you are done! TRIM will now periodically run because of the discard mount-option in /etc/fstab. If you want to trigger a TRIM run manually first time, you can run fstrim -v / as root.

Installing Arch with LUKS and Btrfs (EFI)

NOTE: This post has been updated 2017-05-30 to use systemd-boot instead of GRUB.
NOTE: This post has been updated 2019-03-08 to skip using LVM since Linux kernel 5.0 allows swap file on Btrfs. Also using systemd-init.

I did the steps below to install my Arch for the first time, because I wanted to use Btrfs and LUKS, and also enable swap.

Start Installation CD/USB.
Set up keymap (see available keymaps with ls /usr/share/kbd/keymaps/i386/qwerty):
loadkeys sv-latin1
And start dhcp-request if you haven’t received an IP-address (check with ip addr):
dhcpcd
And now the fun part, partitioning!
Open up gdisk to create partitions for EFI and /boot:
gdisk /dev/sda
o (Create a new empty GUID partition table (GPT))
Proceed? Y

Create partitions:
n (Add a new partition)
Partition number 1
First sector 2048 (default)
Last sector +512M
Hex code EF00

n (Add a new partition)
Partition number 2
First sector 2099200 (default)
Last sector (press Enter to use remaining disk)
Hex code 8300

It should look something like this (print with p):
Number Start (sector) End (sector) Size Code Name
1 2048 1050623 512.0 MiB EF00 EFI System
2 1050624 500118158 238.0 GiB 8300 Linux filesystem

If everything looks good, save and quit:
w
Y

Set up the encryption container:
cryptsetup luksFormat /dev/sda2
Are you sure? YES
Enter passphrase (twice)

Open up the container:
cryptsetup --allow-discards --persistent open /dev/sda2 btrfs-system

Time to format everything:
mkfs.vfat -F32 /dev/sda1
mkfs.btrfs -L btrfs /dev/mapper/btrfs-system

Create Btrfs subvolumes:
mount /dev/mapper/btrfs-system /mnt
btrfs subvolume create /mnt/root
btrfs subvolume create /mnt/home
btrfs subvolume create /mnt/swap
umount /mnt
mount -o subvol=root,ssd,compress=lzo,discard /dev/mapper/btrfs-system /mnt
mkdir /mnt/{boot,home,swap}
mount -o subvol=home,ssd,compress=lzo,discard /dev/mapper/btrfs-system /mnt/home
mount -o subvol=swap,ssd,discard /dev/mapper/btrfs-system /mnt/swap

Time to create the swap:
truncate -s 0 /mnt/swap/swapfile
chattr +C /mnt/swap/swapfile
dd if=/dev/zero of=/mnt/swap/swapfile bs=1M count=8192 status=progress
chmod 600 /mnt/swap/swapfile
mkswap /mnt/swap/swapfile
swapon /mnt/swap/swapfile

And finally the /boot volume:
mount /dev/sda1 /mnt/boot

Installation:
pacstrap /mnt base base-devel btrfs-progs vim efibootmgr sudo zsh zsh-completions grml-zsh-config intel-ucode linux dhcpcd

Generate fstab:
genfstab -U /mnt > /mnt/etc/fstab
It should look something like this (genfstab -U /mnt):
UUID=5f55843f-d4ef-4c9c-bb43-d6ceb0d99c4d / btrfs rw,relatime,ssd,compress=lzo,space_cache,subvol=root,discard 0 0
UUID=5f55843f-d4ef-4c9c-bb43-d6ceb0d99c4d /home btrfs rw,relatime,ssd,compress=lzo,space_cache,subvol=home,discard 0 0
UUID=5f55843f-d4ef-4c9c-bb43-d6ceb0d99c4d /swap btrfs rw,relatime,ssd,space_cache,subvol=swap,discard 0 0
/swap/swapfile none swap defaults 0 0
UUID=AB0E-6CD2 /boot vfat rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro 0 2

Setting up stuff:
arch-chroot /mnt /bin/zsh
echo computer_name > /etc/hostname
chsh -s /bin/zsh
ln -sf /usr/share/zoneinfo/Europe/Stockholm /etc/localtime (See available timezones with ls /usr/share/zoneinfo)
vim /etc/locale.gen (uncomment en_GB.UTF-8 and sv_SE.UTF-8, or other locales that you want)
locale-gen
echo LANG=en_GB.UTF-8 > /etc/locale.conf
echo KEYMAP=sv-latin1 > /etc/vconsole.conf
passwd

Change/add the following to /etc/mkinitcpio.conf:
MODULES=(crc32c-intel)
HOOKS=(base systemd autodetect modconf block sd-encrypt btrfs resume filesystems keyboard fsck)

Generate mkinitcpio:
mkinitcpio -p linux

Run the command below to initialize systemd-boot, the path is your EFI-partition.

bootctl --path=/boot install

Run the following command to get the UUID of your disk, this is needed for systemd-boot:

lsblk -o name,uuid
NAME UUID
sda
├─sda1 AB0E-6CD2
└─sda2 b6cde26f-a4de-4f2e-b973-57c8fbe8813b
└─btrfs-system 5f55843f-d4ef-4c9c-bb43-d6ceb0d99c4d

Look for “sda2” and take note of the UUID of this partition.

Create the file /boot/loader/entries/arch.conf with the following content, or as you have your partitions set up:
title Arch Linux
linux /vmlinuz-linux
initrd /intel-ucode.img
initrd /initramfs-linux.img
options rd.luks.name=b6cde26f-a4de-4f2e-b973-57c8fbe8813b=btrfs-system luks.options=discard root=/dev/mapper/btrfs-system rw rootflags=subvol=root quiet

Edit the file /boot/loader/loader.conf:
timeout 3
default arch.conf

Done, rebooting time!
exit
umount -R /mnt
reboot

Installing KDE (personal preferences, might not apply to your setup!):
systemctl start dhcpcd (Starts DHCP so that you can download packages)
pacman -S networkmanager sddm
systemctl enable NetworkManager sddm
useradd -m -g users -G wheel username
passwd username

Add your user to sudo (edit /etc/sudoers):
username ALL=(ALL) ALL
Intel-specific GPU drivers and xorg. You might have to change xf86-video depending on your GPU vendor or if you want Wayland instead:
pacman -S xf86-video-intel xorg-server (for laptops: xf86-input-synaptics)
pacman -S plasma-meta ttf-dejavu ttf-droid ttf-liberation ttf-freefont konsole (select defaults on package selections)

Optional packages that you might want:
pacman -S kate pulseaudio yakuake firefox thunderbird dolphin ark chromium kodi feh conky firewalld unrar unzip zip git pavucontrol nfs-utils alsa-utils mpv openssh gimp spectacle lm_sensors redshift bind-tools whois krdc freerdp kcalc
If you want to install steam you must enable multilib, edit /etc/pacman/ and uncomment:
[multilib]
Include = /etc/pacman.d/mirrorlist

Install Steam:
pacman -Sy steam
And finally the last reboot!
reboot

After reboot, change login shell in the top-left to Plasma, and login.

All done! Now install everything else you might want :)

If you did something wrong and the OS doesn’t start correctly, you can start the USB/CD again and write the following to mount all things again:
loadkeys sv-latin1
cryptsetup luksOpen /dev/sda2 btrfs-system
mount -o subvol=root,ssd /dev/mapper/btrfs-system /mnt
mount -o subvol=home,ssd /dev/mapper/btrfs-system /mnt/home
mount -o subvol=swap,ssd /dev/mapper/btrfs-system /mnt/swap
swapon /mnt/swap/swapfile
mount /dev/sda1 /mnt/boot
arch-chroot /mnt /bin/zsh

Sources:
My very good friend Dezponia
https://wiki.archlinux.org/index.php/Installation_guide
https://wiki.archlinux.org/index.php/Swap#Swap_file
https://wiki.archlinux.org/index.php/btrfs
https://wiki.archlinux.org/index.php/Mkinitcpio#Common_hooks