Skip to content

Instantly share code, notes, and snippets.

@myyc
Last active October 26, 2024 20:06
Show Gist options
  • Save myyc/9595b520a4c564bef8143a86582f1ea1 to your computer and use it in GitHub Desktop.
Save myyc/9595b520a4c564bef8143a86582f1ea1 to your computer and use it in GitHub Desktop.
Arch Linux setup with all the good stuff (Plymouth, encryption, systemd-boot etc.)

I've used this guide through 2024 despite archinstall and it's still more or less valid. After having used archinstall twice and having encountered obscure issues (luksOpen taking ages, or slow reboots in general) I switched back to a manual setup and it seems to be almost as straightforward.

Always refer to the official guide in case of doubt.

First things first

One important thing first: the environment you will encounter on the live image is very different from what you'll end up installing, some things are significantly easier there: e.g. wifi tools come pre-installed, the default shell is a pimped zsh with nice completions, and so on. We'll keep this in mind where it's important.

I assume you haven't downloaded the setup image from a dodgy website so you don't really have to verify it (I wonder how many people do that).

The first thing you should do is set your preferred console keyboard layout with loadkeys, unless the default one, us, is the one you want.

# ls /usr/share/kbd/keymaps/**/*.map.gz  # look up the possible values
# loadkeys no                            # grab one of the file names, minus the extension

As above, we assume you're using EFI, to check this

# ls /sys/firmware/efi/efivars

If this throws any error you should stop here and stick to the official guide.

Connecting to the internet is not the same procedure during the installation phase as it will be later. The install iso has a bunch of closed source modules embedded so it should recognise your wifi card out of the box. If it doesn't, grab an ethernet cable and your favourite dongle in case you don't have an ethernet port.

  • Ethernet should work once you plug the cable
  • For Wifi you should use iwctl

Test the connection to be safe.

Update the system clock (so vintage)

# timedatectl set-ntp true

Partitioning the drive

Now it's time to partition the disks.

I will assume you're only installing Linux on your machine. If you're dual booting and already have an EFI partition then make your own considerations (size, and so on).

In a previous version of this tutorial I mentioned a few possibilities, LUKS, LVM, swap partition, swapfile. It's unnecessary to discuss all of them, so I'll just make the simplest choice for you: a single encrypted partition, and a swapfile inside it. No use bothering with LVM, and no use bothering with fixed-size swap and two partitions.

Nevertheless, start with the efi partition. This time we're not doing a separate /boot partition, and only put UKIs there, so we don't need 500MB. 200MB are enough. 300 maybe to be safe.

Use cfdisk to partition the drive. If the disk is already partitioned (as above) you shouldn't do much, otherwise you need to create a new GPT partition table. As mentioned, allocate at least 200M to your efi partition, which should be the first, and set EFI as its type, then create a big Linux partition for the rest of the space. Save and quit.

Now it's time to create the encrypted volume. We'll assume that sda1 is your efi partition and sda2 is the Linux one you created above, but with NVMe SSDs it's possible that your drive will be called nvme0n1 so you'll have nvme0n1p1 as efi and nvme0n1p2 instead of sda2.

# cryptsetup -y -v luksFormat /dev/sda2  # or /dev/nvme0n1p2
# cryptsetup open /dev/sda2 main   # use whichever name you want but it needs to match below

This will just create "encrypted space". From here you can either create a partition (mkfs.ext4 /dev/mapper/main) and mount it (mount /dev/mapper/main /mnt), that's pretty much it.

Regardless of your setup during the installation phase whatever is your / partition should be mounted on /mnt.

As for the swap file, nowadays there are a few options, and the good thing about it is that you don't have to worry about it now. For later, here are two pointers.

If you use zram it'll presumably have higher performance, but you'll lose hibernation, so pick whichever you like. This is reversible anyway (unlike using partitions).

Anyway:

  • The root partition is created and mounted.
  • The EFI partition is mounted at the right place (/mnt/efi, not /efi).

If both of the above are true, we can move to the next section. Some details of this setup will be crucial to make sure that the system boots, we'll mention them later.

The actual installation

This is the easy part, but you probably still need a couple of pointers.

Install the base system

# pacstrap /mnt base linux linux-firmware

This basically installs only the base system plus the kernel plus essential Linux firmware: it won't install anything like "my webcam's firmware" or "external wifi drivers". We'll do that in a second.

Generate your fstab file for this setup:

# genfstab -U /mnt >> /mnt/etc/fstab

This basically looks at what's mounted and where and generates a matching /etc/fstab. Edit the paths if they're wrong, e.g. if the efi partition is mounted to /mnt/boot instead of /boot, keep in mind that this is in what will become your setup, so no /mnt there – hence genfstab /mnt.

Now you can chroot to /mnt and we'll operate as if everything is installed.

# arch-chroot /mnt

Set the time zone and sync the hardware clock:

# ln -sf /usr/share/zoneinfo/Europe/Oslo /etc/localtime    # pick whichever time zone
# hwclock --systohc

Now you need to think of what you need to install in the system to make sure that once you reboot you're not in some bizarre desert island. As I mentioned earlier, exotic wifi stuff isn't installed by default, but luckily many things are in the Arch Linux repository. For instance, if you need the Broadcom wl module:

# pacman -S linux-headers broadcom-wl-dkms

Repeat this step for every peripheral you know that you will need (minus linux-headers of course): the most crucial one in general is just the WiFi because keyboards and screens should work out of the box and maybe you just miss the nvidia driver and stuff like that if you have a Nvidia card, but since the open source driver is installed already, you should be fine for minimal usage.

Once you're sure that you have a working WiFi module installed, this is also the right time to figure out how you want to use your new setup: if you want to fine tune it yourself and install whichever minimal WM (e.g. i3), have fun, but be careful to install whichever tools you need to connect to the internet. If you want to use gnome on the other hand, just run:

# pacman -S gnome

And this should install everything on its own. If you use gnome you need to have Network Manager installed even though these days systemd has a thingy that is able to control the network. Check if iwd and networkmanager are installed.

# pacman -Q iwd networkmanager

If not, well, pacman -S etc. etc..

As a rule of thumb, Arch Linux doesn't enable stuff for you after you install it, when it comes to global systemd configuration, so do this:

# systemctl enable NetworkManager.service

This makes sure Network Manager starts when you reboot, so that then you can use GNOME's GUI to configure your wifi, or wired connection.

One thing I'd also do is adding this to /etc/NetworkManager/NetworkManager.conf:

[device]
wifi.backend=iwd

In a modern machine there is no reason not to use iwd.

Optionally, you should edit /etc/locale.gen and uncomment your favourite locale, e.g. en_GB.UTF-8. Then run locale-gen and edit /etc/locale.conf and put LANG=en_GB.UTF-8. Check out /etc/locale.gen for other possible options.

Create a root password:

# passwd

This is also a good moment to create your own user:

# useradd -m username
# passwd username

This is a matter of taste but I'd install your usual comfort zone packages now, e.g. your favourite shell, your favourite text editor and so on. Not to imply that since you'll fuck up your boot loader configuration it's better to have a nice text editor and shell so that you won't be too annoyed when you'll have to fix your mistakes, you never know what life has in store for you so it's just nicer to face adversities from a nice zsh prompt.

Boot loader and mkinitcpio

Alright: this is where you can't fuck stuff up. If you fuck stuff up here your system won't boot. Typically when this happens it's recoverable from the install medium you used, via arch-chroot and so on. With encrypted setups doing this is annoying because on every reboot with the install medium you always need to open the volume, mount the root partition and so on, so every fuckup adds minutes to the debugging process. To add insult to injury, debugging is often hard because the messages aren't very helpful.

Having said that, here we go.

What I'd do first is check the guide.

This is what my /etc/mkinitcpio.conf looks like:

HOOKS=(base systemd plymouth autodetect microcode modconf kms keyboard sd-vconsole sd-encrypt block filesystems fsck)

Note: microcode has been moved into mkinitcpio so make sure to install the relevant package for your system (intel-ucode or amd-ucode).

You should already install plymouth from pacman because it doesn't hurt (it won't be enabled yet).

Now it's a good time to run your first mkinitcpio:

# mkinitcpio -P

Chances are that this has been run already by several of the commands we ran earlier.

We'll use systemd-boot. A few principles:

  • It will be installed in your EFI partition.
  • It will grab loader entries from /efi/loader/entries/ so once it's installed we'll make sure you have a valid one there.

Install it:

# bootctl install

You should then enable systemd-boot-update.service to keep it up to date.

You now need to create a UKI. A UKI is basically a combination of kernel, microcode, initrd and whatever mkinitcpio decides to put in "the thing that boots your computer". You might be used to command line parameters – explanation on what to put there follows. A UKI bundles those in the image. The downside is that you lose the flexibility (e.g. you can't do old-school stuff like switching off splash on boot, single user, these sorts of things). The upside is more security, nobody can touch your boot process.

In order to do so you just need to enable it in /etc/mkinicpio.d/linux.preset:

ALL_kver="/boot/vmlinuz-linux"

PRESETS=('default')

default_image="/boot/initramfs-linux.img"
default_uki="/efi/EFI/Linux/arch-linux.efi"

This is enough, and running mkintcpio -P should pick it up and you should see your UKI in /efi/EFI/Linux.

The crucial thing is to get it to boot, and this is where you should not fuck up your cmdline parameters.

Add /efi/loader/entries/linux.conf:

title Linux
efi /EFI/Linux/arch-linux.efi

You now need the command line parameters, these go in /etc/kernel/cmdnline. There are other possible paths but this is fine so let's ignore the others.

rd.luks.name=[PLACEHOLDER_1]=[PLACEHOLDER_2] root=[PLACEHOLDER_3] rw  # and all the other params

Now with the three placeholders. We need to rewind a bit and do some matching. The third placeholder is the easy one: this is the root partition's "device", the "thing that you mount". So /dev/mapper/main or whatever you decided to cryptsetup open.

Let's run blkid:

# blkid
/dev/nvme0n1p1: UUID="284C-3A64" BLOCK_SIZE="512" TYPE="vfat" PARTUUID="0794ef09-5eb8-d144-b103-bc7b975f8963"
/dev/nvme0n1p2: UUID="79ac497a-7eac-4f16-af63-f362c52ed44c" TYPE="crypto_LUKS" PARTUUID="58319ad0-043c-fc48-9c4b-c466484d1135"
/dev/mapper/main: UUID="fd884ff1-12a0-4289-89ce-11ca73f4af89" BLOCK_SIZE="4096" TYPE="ext4"

The first and second placeholder are, respectively, the UUID of the outermost layer of the partitions onion:

rd.luks.name=79ac497a-7eac-4f16-af63-f362c52ed44c=main root=/dev/mapper/main rw

Triple check that you're not using the UUID of /dev/mapper/main. If you do that, your computer won't boot.

main is the name of whatever you picked earlier with cryptsetup: unclear if there needs to be consistency (there probably has to), so remember the general idea and keep tabs.

To be safe, run mkinitcpio -P again (no use not doing so).

Now you can reboot and cross your fingers.

I have rebooted and it doesn't work

If you see systemd-boot's prompt (i.e. you see a Linux entry) but then booting hangs the mistake should be almost certainly because you messed up ID's and names. Don't despair, it's fixable without having to start from scratch. Boot from the install medium and mount the root and boot partitions.

  1. Check mkinitcpio.conf just in case, compare with the HOOKS above.
  2. Check the UUID's in /etc/kernel/cmdline (or whichever the UUIDs).

Fixing these mistakes is very annoying because each reboot is time consuming.

I have rebooted and it works

Well done, there isn't much left to do.

Optionally, you should set your hostname, since you're using systemd:

sudo hostnamectl set-hostname myhostname

From here on I'll take a few things for granted, like that GNOME works and that your main user can sudo (and of course that sudo is installed), etc.

Plymouth

Finally, plymouth has it out of the AUR. But themes have not. This is a good opportunity to install an AUR helper, i.e. a piece of software that handles installation from the AUR automatically. I recommend yay but you might have a different opinion. Have a look here on how to install it.

$ yay -S plymouth plymouth-theme-arch-charge
$ sudo plymouth-set-default-theme arch-charge

Before rebooting you should also tell mkinitcpio that you need to load your graphics module. This will depend on which card you have. I can only vouch for Intel and NVIDIA. You need to edit the MODULES section of mkinitcpio.conf:

MODULES=(nvidia nvidia_modeset nvidia_uvm nvidia_drm)    # for nvidia cards
MODULES=(amdgpu)                                         # for amd cards
MODULES=(i915)                                           # for intel cards

You also need to add quiet splash to /etc/kernel/cmdline.

Once that is done, mkintcpio -P will be enough: you can reboot now and you should be able to see the splash screen on shutdown already.

Secure boot

Briefly, secure boot is a feature that only allows to boot signed files. If a file isn't signed the bootloader rejects it. The keys are stored in a module in your computer that only the BIOS can access, and, of course within your hard drive (or wherever else you want to store them, concretely).

In order for this to be secure, you must do the following:

  1. Secure boot must be enforced
  2. Your BIOS must be protected with a password
  3. The partition containing your keys must be encrypted

If 1. isn't true, someone could replace your signed kernel with a malicious one that you will boot without knowing. If 2. isn't true, someone could access your bios, disable secure boot, and you're back to point 1. If 3. isn't true, someone could sign a malicious kernel with your keys, without the need to tamper with the BIOS.

To configure secure boot there are two options. One is manual but it gives you a bit more control (but it is clunky). The other one is way easier, and it involves sbctl (which you need to install).

I will detail the essential procedure, as instructions are not universal.

  • Create keys with sbctl create-keys.
  • Try sbctl enroll-keys -m -f. This command puts your newly created keys plus the Microsoft ones and the ones recommended by the firmware, into the BIOS. Chances are that it might fail because you need to be in "setup mode". This, in some cases, requires wiping the secure boot configuration, and with it the pre-enrolled keys. Check around if your computer needs them urgently to boot (it probably doesn't). If it doesn't, reboot into the BIOS, put your computer in setup mode (in the Framework Laptop case this is achieved by erasing all secure boot settings), then re-run the command again. If it succeeds, move on. If it fails, you'll need to dig more.
  • Run sbctl verify and you'll have a list of files that you need to sign. Typically the bootloader (/efi/EFI/BOOT/BOOTX64.EFI), the kernel UKI (/efi/EFI/Linux/arch-linux.efi) and /efi/EFI/systemd/systemd-bootx64.efi. I don't know what the difference between the two boot64x.efi is but sbctl verify shows you that it should get signed.
  • Sign all of them with sbctl sign -s (don't forget -s as it saves the path to the database so that every kernel/systemd upgrade will trigger a signature.
  • Run sbctl status and sbctl verify and check that everything makes sense.
  • Reboot and enable secure boot.

Fingerprint reader

If you have a fingerprint reader, there are a few ways around it, the best one is using pam-fprint-grosshack. Install it from the AUR.

Then you need to add this line above everything else (minus the initial comment) in a few files:

# add this in /etc/pam.d/sudo, /etc/pam.d/system-local-login and /usr/lib/pam.d/polkit-1

auth        sufficient  pam_fprintd_grosshack.so

Once you've done that, you should enroll your fingerprints. You can do it using GNOME. If you aren't able you probably need to wipe the reader. Depending on which model, there are a few tools on the internet that do that.

Hibernate

This is also something you might need regardless of whether you're using a laptop.

Add the resume hook between filesystems and fsck in mkinitcpio.conf which you should be best mates with by now, and run mkinitcpio -P.

You must also tell the bootloader where to resume from, by adding the resume= kernel option to the loader entry.

If you're using a swap partition resume=UUID=PLACEHOLDER where PLACEHOLDER is of course the UUID of the swap partition (sudo blkid to obtain it). If you're using a swap file the logic is a bit different. resume should point to the device containing the file, e.g.:

resume=/dev/mapper/main    # in the luks example above

Only one of those two of course. Then you should add a resume_offset parameter that you obtain this way:

$ sudo filefrag -v /swap
Filesystem type is: ef53
File size of /swap is 34359738368 (8388608 blocks of 4096 bytes)
 ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0..       0:     514048..    514048:      1:
   1:        1..   10239:     514049..    524287:  10239:             unwritten
   2:    10240..  272383:     557056..    819199: 262144:     524288: unwritten

It should be the first physical_offset value, i.e. in this case

resume_offset=514048

Since the system hasn't been booted with a kernel supporting hibernation even if you regenerate the initramfs now (mkinitcpio -P) you'll need to reboot to be able to use this feature.

This is pretty much it, I hope it's useful.

@zearp
Copy link

zearp commented Mar 3, 2023

I got here searching on mounting my luks volume after I messed up grub on my fresh Arch install. Decided to follow your guide to the letter and it works great in 2023 on my 2012 Macbook. No issues with system-boot surprisingly! No caveats found and no changes were needed. Arch setup doesn't change much I guess 😅

Thanks for sharing it was indeed useful, fun and educational!

@myyc
Copy link
Author

myyc commented Mar 3, 2023

@zearp happy that it helped you :) FYI, the new arch installer does all of this for you and i didn't use my own guide myself for my new laptop but yeah, it does help understand how luks + systemd-boot works i think :)

edit: for some bizarre reason a software update broke my laptop configuration and i had to revert to this :) still applies it seems!

@neonyirenda
Copy link

Wish I saw this before I thought Arch Install would have made it all easy but unfortunately kept failing until I followed a guide to just get it to work out of frustration, and now I'm working backwards on the things I wanted to initially do. Thanks you just sorted my Plymouth problem well not the same way but a lot more pointer than I could get anywhere.

One thing I can't deny I don't mind atm is arch-chroot < easiest chroot I've done in never until yesterday.

@averagedebianuser
Copy link

averagedebianuser commented Sep 26, 2023

Thanks for the guide, helped me switch from GRUB to systemd-boot and from busybox mkinitcpio to systemd mkinitcpio.

Also, this is a really specific case but if you have an extended boot partition (ESP and /boot on separate partitions), make sure the /boot is formatted to FAT32 instead of ext4. GRUB supports booting from ext4 /boot partition but systemd-boot doesn't (atleast without a lot of tinkering).

Boot into live iso, chroot into system (make sure to mount root, /boot and ESP), uninstall whatever bootloader you currently have, copy everything from /boot to another directory, format /boot to FAT32, copy everything bac, generate a new fstab (exit chroot, genfstab -U /mnt > /mnt/etc/fstab, chroot again) and reinstall the bootloader. Make sure it's bootctl --esp-path=(ESP mount point) --boot-path=/boot install, -boot-path argument is needed if ESP and boot are separate partitions otherwise it assumes the ESP is the /boot directory

Also if you're using separate /boot and ESP make SURE you put your boot entry in /boot/loader/entries/ instead of <ESP>/loader/entries/ but keep the rest of the configuration in <ESP>/loader/ otherwise systemd-boot won't find the kernel + initramfs

This took me like 2 hours to figure out. I'm using a separate /boot and ESP to work around a really weird UEFI implementation.

@myyc
Copy link
Author

myyc commented Jul 26, 2024

@averagedebianuser i just reinstalled arch and revamped the guide a bit according to my specific use case but i think it's broad enough. i think that with secure boot and UKIs being more common place it does make sense to have /efi as the only accessible partition, with /boot being just a regular directory in the encrypted file system. it also makes things simpler because it allows /efi to be shared between operating systems without all the trash that /boot usually has on linux.

@djallits
Copy link

djallits commented Jul 31, 2024

Since you are using systemd-boot, you can safely drop the base hook from your mkinitcpio hooks config. Per the wiki, base is "[o]ptional when using the systemd hook as it only provides a busybox recovery shell."

I also believe the block hook is supposed to be called before the sd-encrypt hook, per the same wiki article.

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