Skip to content

Instantly share code, notes, and snippets.

@crabdancing
Last active July 17, 2022 07:51
Show Gist options
  • Save crabdancing/6c29f4c46c74cbda28524f9973d9c219 to your computer and use it in GitHub Desktop.
Save crabdancing/6c29f4c46c74cbda28524f9973d9c219 to your computer and use it in GitHub Desktop.
Installing Arch Linux (2020)

intro

I decided recently that I'm done being a boomer. Most decent machines have like 16GB of RAM at minimum, so I can afford to run KDE instead of XFCE. And like everything I own has had EFI support for years. So I should probably start building my Arch Linux installs with support for that, instead of MBR crap.

The one thing I wish I could do is encrypt the boot partition, but that slows down boot time a fair bit in my experience. When you do boot encryption, GRUB has to decrypt your password (which it doesn't do very efficiently, so it takes a bit of time to unlock your key), then hands it off to initramfs to then unlock main boot partition. This obviously kinda sucks turds. You're remounting stuff over and over again. Ideally you only want it mounted once, maybe twice if you have to.

The way GRUB prompts for a password is also quite awkward -- nothing like the smooth UI you can get from an initramfs prompt. By default, if you enter the wrong password once, it just gives up and moves straight to a GRUB recovery console. Very frustrating.

So instead, I'm opting for self-signed secureboot solutions, with pacman/mkinitcpio/grub-mkconfig hooks to automatically sign boot files when they're changed. I'll update this with my method soon enough.

These instructions detail my process for my medium security Linux devices. It includes:

  • GPT partition
  • GPT-embedded GRUB install with EFI boot
  • dmcrypt container for main OS
  • BTRFS
  • KDE desktop environment with semi-decent portaled containerization
  • FISH as default shell
  • encrypted hibernation support with easily rescalable swap file.
  • only a SINGLE encryption key needs to be unlocked, not like, 5.
  • systemd-based initcpio (yes, I am horny for dat D.)

This setup is of average security, I'd say. I wouldn't say it's at the level of top secret leet superspy levels. I plan to write a walkthrough of how to set that up too, down the line.

The goal of this is to produce a practical balance of security and usablity for the distinguished OCD college student. You will note that unlike other setups, this does not have like 5 different header keys to unlock before boot finishes. It is meant to load quickly. If your Arch install takes longer to boot than Windows 10, you have done something wrong.

cli

connecting to wifi via CLI

This has always been pretty intuitive in Arch. I'm actually quite a fan of the new iwctl utility they introduced to replace wifi-menu -- it feels both intuitive and flexible to use.

Anyway, to get a list of your wifi devices, do:

iwctl station list

I happen to see wlan0. If you see some other name instead, substitute wlan0 with that.

iwctl station wlan0 scan
iwctl station wlan0 get-networks

You get some very cute and useful output that even shows you a bar graph for each access point's signal strength, and their security too. I wish NetworkManager had a CLI like this.

iwctl station wlan0 connect [[your access point name]]

You wil be prompted for a password, if it needs one. If you make a mistake typing it, just enter the command again. And that's it! You'll be connected in no time.

partitioning

Anyway. Let's start. Delete the partition table:

dd if=/dev/zero of=/dev/sdX count=10 bs=1M

I wouldn't zero over or randomize the whole disk unless you're eager to waste write cycles. Unless your old OS wasn't encrypted, but you've have to be a real noob to do that, right?

Right?

Look, if you want to hide the free space, you can do the same dd command except with no count limit and source from /dev/urandom. And make sure you have haveged daemon so you can get enough entropy reasonably quickly. Nowadays Arch Linux ISOs come with it already enabled and running, so it's even easier. Or if you wanna be really secure, substitute dd with shred. It'll also waste even more write cycles, yay!

Okay, partition table go byebye. We make a new one.

Unlike most Arch users, I like to use cfdisk, because it's easier to remember how to use what with its fancy curses UI.

cfdisk /dev/sdX

It'll prompt you for the label you want. Pick gpt.

Make you first partition. You'll be prompted for the size of it. Tell it 512M. It starts at sector 2048 by default, and ends at +512M, being 512M in length. This is fine for our purposes. Then set the type to EFI.

Next, make a Linux filesystem partition, size of 1G. This of course will contain our (sadly) unencrypted boot partition with its early userspace & kernel images, along with GRUB config.

Finally, make another Linux filesystem partition filling the rest of the space. By default, cfdisk will make partitions fill the remaining space, so this is easy and quick to do.

So you've now got sdX1 (EFI), sdX2 (boot), and sdX3 (root).

The next step is to encrypt. You can put all sorts of options here to improve your security. If you use a weak password, I recommend increasing itertime so that it's harder to get at the key (at the cost of slower unlocking time). Do NOT make the mistake of trusting cryptsetup benchmarks. You're going to end up with something suuuper slow, in my experience. Or maybe I'm just dumb and did it wrong, dunno.

cryptsetup luksFormat /dev/sdX3

Time to open the container...

cryptsetup open /dev/sdX3 root

Make sure if you're installing to a SSD, BTRFS has turned of metadata dup. It will do this automatically most of the time.

mkfs.btrfs /dev/mapper/root

These options are the ones you want, especially for SSDs. noatime keeps us from writing updating timestamps over and over again, which can shred your SSD's write cycles.

mount /dev/mapper/root /mnt -o noatime,autodefrag,space_cache

Okay. We made an encrypted BTRFS container and mounted it under /mnt.

We're going to want a special @root subvolume, and have the main subvolume mounted under /@ or something. That way we don't have to deal with awkwardly having e.g. backup subvolumes inside our root subvolume.

btrfs sub create /mnt/@root

Now we can unmount, and mount the subvol for installation.

By default, BTRFS sets the toplevel subvol (0) as default -- that's what you see when you mount. We can tell the partition to treat a different subvolume as default, though. Let's tell it to treat @ as default.

btrfs subvol list -p /mnt

In this case, I found that the subvolume had an ID of 262. You can tell because it's the first part of the line.

btrfs subvol set-default [subvolume ID] /mnt
umount /mnt
mount /dev/mapper/root /mnt

You can use -o subvol=@root with mount, if you don't want to override the default subvolume.

Anyway, next I must mount toplevel subvolume in a subdirectory for easy access.

mkdir /mnt/@
mount /dev/mapper/root /mnt/@ -o subvolid=0

You'll also notice that if you ls the contents of /mnt/@ you see the @root subvolume, containing the same contents as /mnt. Let's add a few more subvolumes -- starting with one for swap.

btrfs subvol create /mnt/@/@swap
chattr +C /mnt/@/@swap

Here, +C disables copy-on-write features.

You're also going to want to create your actual swap file. Here, you wanna replace 16G with a size corresponding to the amount of primary memory your device has.

fallocate /mnt/@/swap.img -l 16G
chmod 600 /mnt/@/swap.img
mkswap /mnt/@/swap.img
swapon /@/@swap/swap.img

Note that you shouldn't have to bother with adding the /@/@swap/swap.img none swap sw 0 0 line to your fstab, since genfstab should take care of that for you. :)

We need to init the other two partitions, too. The machine's EFI firmware will want to read EFI data from a FAT32 partition, so...

mkfs.fat -F32 /dev/sdX1
mkfs.ext4 /dev/sdX2

The next order of business is to mount boot and EFI.

mkdir /mnt/boot
mount /dev/sdX2 /mnt/boot
mkdir /mnt/boot/efi
mount /dev/sdX1 /mnt/boot/efi

We can now begin the actual installation.

installation

Note: this package list is heavily embelished with key workflow stuff I always forget to install later on. For you, your ideal package list might be very different. If you want to skip arch-install-scripts, make sure to call genfstab before the chroot. It should work just as well either way.

pacstrap /mnt base base-devel grub btrfs-progs git intel-ucode linux-lts linux-firmware iwd fish wget curl vim tmux nmap arp-scan efibootmgr man apparmor python python-sh
genfstab -U /mnt >> /mnt/etc/fstab

And now we change-root in! From now on, everything we're doing happens 'inside' the install, using the binaries we just installed.

arch-chroot /mnt fish

accounts & auth

Before anything else, make sure to give yourself shell account access, and set your preferred terminal.

useradd ada
usermod -aG wheel ada
mkdir /home/ada
chown ada:ada /home/ada
passwd ada
passwd root
usermod -s /usr/bin/fish ada
usermod -s /usr/bin/fish root

I can hear the distant screams of POSIX purists, but I'm too high on kratom & semax to give a fuck.

Oh, speaking of annoying purists -- you're probably going to want to:

chattr -i /etc/sudoers
chmod 600 /etc/sudoers
vim /etc/sudoers

and uncomment the line that says %wheel ALL=(ALL) ALL.

While we're on the topic of editing auth stuff...

vim /etc/pam.d/su

And uncomment the line that says something like: auth required pam_wheel.so use_uid

I dunno why it's not the default behavior to do this. I bet there are loads of Linux systems with weak root passwords that just get brute forced to root this way. Tsk tsk.

Locale & language

timedatectl set-ntp true
timedatectl set-timezone America/Los_Angeles

Of course, you should replace America/Los_Angeles with whatever unix timezone you're in. You can look at all the options under /usr/share/zoneinfo.

grub & early userspace

We install GRUB, generate filesystem table, and generate our GRUB configuration:

grub-install /boot/efi --target=x86_64-efi --bootloader-id=ArchLinux

We'll also want to edit /etc/mkinitcpio.conf:

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

(FYI, hook order matters.)

Aaand rebuild initcpio...

mkinitcpio -P

We need to reconfigure GRUB before preceding. It's GRUB's job to tell the kernel what to boot into, so let's make sure Linux knows we want it to decrypt our main partition.

vim /etc/default/grub

Here is where I like to remove loglevel=3 quiet. I don't know about you, but I like to know when my computer is doing stuff, and what stuff it's doing. I also recommend decreasing GRUB_TIMEOUT. Also, have you tried setting the colors to magenta? I think it looks really pretty. I usually go for magenta/black for unselected and light-magenta/black for selected.

Also don't forget to uncomment GRUB_ENABLE_CRYPTODISK=y!

And now comes GRUB_CMDLINE_LINUX. What you really want here is a metric asston of kernel arguments that should look something like this:

GRUB_CMDLINE_LINUX="rd.luks.name=[[CRYPT_UUID]]=root rd.luks.options=timeout=300s resume=/dev/mapper/root resume_offset=[[BTRFS_SWAP_FILE_OFFSET]] apparmor=1 lsm=lockdown,yama,apparmor

Some explanations:

  • GRUB_CMDLINE_LINUX

    • The line that determines what kernel args we pass to the Linux kernel itself. This gives the kernel lots of contextual operation cues, as well as holding data for userspace applications, especially in initcpio.
  • rd.luks.name

    • This tells our sd-encrypt hook which device to decrypt, and what map name to apply to it. It's functionally the same as cryptsetup open /dev/disk/by-uuid/[[CRYPT_UUID]] root.
  • rd.luks.options

    • Some configuration options for our sd-encrypt process. Here, we're using timeout to override the default timeout.
  • resume

    • Here is the block device where the resume data will be stored. Since the kernel doesn't know how to read the block device, we have to give it an offset value to tell how much of the raw block device data to skip before it can start reading the swap data to resume the system.
  • resume_offset

    • The offset we're actually using
  • apparmor

    • Whether to enable or disable apparmor. We're enabling it.
  • lsm

    • Linux Security Module config
    • lockdown
      • makes editing kernel code from userspace harder, helping to prevent rootkitting
    • yama
      • nerf ptrace

You might think you're supposed to substitute those [[]] bits, but actually, no. I wrote a script collection called ArchAid that'll do the work for us. Let's download it.

git clone https://github.com/alxpettit/ArchAid
cd ArchAid

ArchAid is a collection of scripts that operate in two stages. The first is the collection/calculation stage, and the second is the actually inserting info stage. Let's start by grabbing our target UUID.

./grab_crypt_uuid.py /dev/sdX3

Here, of course, /dev/sdX3 represents the third (encrypted) partition of whatever drive you've been targeting.

You'll notice that after running this command, if nothing caught fire, you should have a data/CRYPT_UUID file. This will tell the final script what UUID to insert.

Next, let's move on to calculating our swap offset.

./btrfs_swap_file_calculator.py /@/@swap/swap.img

Finally, we tell the program to insert it into grub's config.

./insert_data /etc/default/grub

Now that we've finished configuring GRUB, it's time to gen its /boot cfg file.

grub-mkconfig -o /boot/grub/grub.cfg

We should probably enable audio, bluetooth, and network support.

pacman -S bluez pulseaudio pulseaudio-bluetooth networkmanager
systemctl enable NetworkManager
systemctl enable bluetooth

gui

Installing the GUI is pretty easy. For instance, since I'm using KDE, I simply do:

pacman -S xorg plasma plasma-wayland-session kde-applications firefox-developer-edition hunspell-en_US code

I like having Xorg and Wayland available, but sadly in my experience you probably wanna have Xorg be your main. (You can switch that from the login screen). Wayland isn't quite there and has some pretty annoying bugs. Hey, at least we're trying, right? We're doing better with Wayland migration than IPV6 support, I can tell you that much.

If you want your GUI to run on start, you do:

systemctl enable sddm

And if you want to run it right now the 'proper' way, do:

systemctl start sddm

fixing FISH+Dolphin bug

Once you get a GUI up, you're going to want to open Dolphin, and press F4 to pull up the FISH terminal. As of 2020, this terminal has some 'issues' with complaining constantly about setting the terminal window. Let's apply my patented dodgy workaround.

Right click on the terminal, and select Edit current profile.... Under Environment:, select Edit.... Finally, add INSIDE_EMACS=true to the bottom of the env var list.

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