Skip to content

Instantly share code, notes, and snippets.

@queeup
Forked from orhun/arch_linux_installation.md
Created February 1, 2024 21:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save queeup/e3522cec11a96338026eccee18e40559 to your computer and use it in GitHub Desktop.
Save queeup/e3522cec11a96338026eccee18e40559 to your computer and use it in GitHub Desktop.
Notes on my Arch Linux installation: UEFI/Secure Boot + systemd-boot, LUKS-encrypted root (XFS), LUKS-encrypted swap (with hibernate & unlocked via TPM)

Notes on my Arch Linux installation

Hardware

  • Lenovo ThinkPad E15G2 (20T8001UTX)
    • AMD Ryzen 7 4700U
    • 8GB RAM
    • 512GB SSD
    • 15.6" FHD
    • Freedos

Known Issues

Preparation

Boot up Arch Linux ISO and do the following:

  • Disable the annoying beep sound: rmmod pcspkr
  • Bring up WiFi via iwctl station wlan0 connect <SSID>
  • Have some coffee ☕

Pre-installation

Select the drive

export DRIVE=/dev/nvme0n1

(Use lsblk to determine the correct drive to install)

Zap the disk

sgdisk --zap-all $DRIVE
-Z, --zap-all
    Zap (destroy) the GPT and MBR data structures and then exit. This option works much like -z, but as it wipes the MBR as well as the GPT, it's more  suitable  if  you  want  to repartition a disk after using this option, and completely unsuitable if you've already repartitioned the disk.

Create the partitions

sgdisk --clear \
       --new=1:0:+550MiB --typecode=1:ef00 --change-name=1:EFI \
       --new=2:0:+8GiB   --typecode=2:8200 --change-name=2:cryptswap \
       --new=3:0:0       --typecode=3:8300 --change-name=3:cryptsystem $DRIVE

Partition types

Check the partitions

lsblk -o +PARTLABEL
NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS           PARTLABEL
loop0         7:0    0 641.6M  1 loop /run/archiso/airootfs 
sda           8:0    1   7.3G  0 disk                       
└─sda1        8:1    1   7.3G  0 part /run/archiso/bootmnt  
nvme0n1     259:0    0 476.9G  0 disk                       
├─nvme0n1p1 259:1    0   550M  0 part                       EFI
├─nvme0n1p2 259:2    0     8G  0 part                       cryptswap
└─nvme0n1p3 259:3    0 468.4G  0 part                       cryptsystem

Format EFI partition

mkfs.fat -F32 -n EFI /dev/disk/by-partlabel/EFI

Encrypt system partition

cryptsetup luksFormat /dev/disk/by-partlabel/cryptsystem

Add an additional LUKS key

cryptsetup luksAddKey /dev/disk/by-partlabel/cryptsystem

Backup LUKS header

If the header of a LUKS encrypted partition gets destroyed, you will not be able to decrypt your data. It is just as much of a dilemma as forgetting the passphrase or damaging a key-file used to unlock the partition. Damage may occur by your own fault while re-partitioning the disk later or by third-party programs misinterpreting the partition table. Therefore, having a backup of the header and storing it on another disk might be a good idea.

cryptsetup luksHeaderBackup /dev/disk/by-partlabel/cryptsystem --header-backup-file /mnt/<backup>/<file>.img

Open the encrypted system partition

cryptsetup open /dev/disk/by-partlabel/cryptsystem system

Encrypt swap partition

To be able to resume after suspending the computer to disk (hibernate), it is required to keep the swap space intact. Therefore, it is required to have a pre-existent LUKS swap partition or file, which can be stored on the disk or input manually at startup.

cryptsetup luksFormat /dev/disk/by-partlabel/cryptswap
cryptsetup open /dev/disk/by-partlabel/cryptswap swap
mkswap -L swap /dev/mapper/swap
swapon -L swap

The following setup has the disadvantage of having to insert an additional passphrase for the swap partition manually on every boot.

However, we will eliminate this by storing the LUKS key in TPM.

Create and mount XFS filesystem

mkfs.xfs -f -L system /dev/mapper/system
mount LABEL=system /mnt

Mount EFI partition

mkdir /mnt/boot
mount LABEL=EFI /mnt/boot

Installation

Install essential packages

pacstrap /mnt base linux linux-firmware

Generate fstab

genfstab -L /mnt >> /mnt/etc/fstab
-L
  Use labels for source identifiers (shortcut for -t LABEL).
# /dev/mapper/system UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
LABEL=system        	/         	xfs       	rw,relatime,attr2,inode64,logbufs=8,logbsize=32k,noquota	0 1

# /dev/nvme0n1p1 UUID=xxxx-xxxx
LABEL=EFI           	/boot     	vfat      	rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,utf8,errors=remount-ro	0 2

# /dev/mapper/swap UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
#LABEL=swap          	none      	swap      	defaults  	0 0
# add this line instead for using the mapped device as swap
/dev/mapper/swap swap swap defaults 0 0

Boot into the system

arch-chroot /mnt

Configure the system

pacman -S vim
# Set the time zone
ln -sf /usr/share/zoneinfo/Europe/Istanbul /etc/localtime

# Set the Hardware Clock from the System Clock, and update the timestamps in /etc/adjtime.
hwclock --systohc

# Uncomment desired locales
vim /etc/locale.gen
# Generate the locales
locale-gen

# Create the hostname
vim /etc/hostname

# Set the root password
passwd

Install network manager

pacman -S netctl wpa_supplicant dhcpcd dialog

Regenerate initramfs

Create a backup of the original config:

cp /etc/mkinitcpio.conf /etc/mkinitcpio.conf.orig

Update HOOKS in /etc/mkinitcpio.conf as follows:

HOOKS="base systemd modconf keyboard block sd-encrypt filesystems fsck"

Regenerate:

mkinitcpio -p linux

Select the CPU architecture

export CPU_ARCH=amd # amd or intel

Install microcode

Processor manufacturers release stability and security updates to the processor microcode. These updates provide bug fixes that can be critical to the stability of your system. Without them, you may experience spurious crashes or unexpected system halts that can be difficult to track down.

All users with an AMD or Intel CPU should install the microcode updates to ensure system stability.

pacman -S $CPU_ARCH-ucode

Install systemd-boot

Make sure the system has booted in UEFI mode and that UEFI variables are accessible:

ls /sys/firmware/efi/efivars

Use bootctl to install systemd-boot into the EFI system partition:

bootctl install
Created "/boot/EFI"
Created "/boot/EFI/systemd"
Created "/boot/EFI/BOOT"
Created "/boot/loader"
Created "/boot/loader/entries"
Created "/boot/EFI/Linux"
Copied "/usr/lib/systemd/boot/efi/systemd-bootx64.efi" to "/boot/EFI/systemd/systemd-bootx64.efi"
Copied "/usr/lib/systemd/boot/efi/systemd-bootx64.efi" to "/boot/EFI/BOOT/BOOTX64.EFI"
Created "/boot/xxxxxx"
Random seed file /boot/loader/random-seed successfully written (512 bytes).
Created EFI boot entry "Linux Boot Manager".

Configure systemd-boot

/boot/loader/loader.conf:

default arch*.conf
timeout 5
editor no
console-mode auto

When using the systemd-based initramfs with the sd-encrypt mkinitcpio hook, simply specify additional rd.luks kernel parameters to unlock the swap partition.

/boot/loader/entries/arch.conf:

title Arch Linux
linux /vmlinuz-linux
initrd /<CPU-ARCHITECTURE>-ucode.img
initrd /initramfs-linux.img
options rd.luks.name=<ROOT-PARTITION-UUID>=system root=/dev/mapper/system rd.luks.name=<SWAP-PARTITION-UUID>=swap resume=/dev/mapper/swap rw
  • <ROOT-PARTITION-UUID>: lsblk -o NAME,UUID | grep nvme0n1p3 | awk '{print $NF}'
  • <SWAP-PARTITION-UUID>: lsblk -o NAME,UUID | grep nvme0n1p2 | awk '{print $NF}'
  • <CPU-ARCHITECTURE>: value of $CPU_ARCH

Update kernel parameters

  • audit=0: disable audit logs
  • acpi_backlight=vendor: prefer vendor specific driver for backlight (see the other options)
  • splash: show splash during boot
  • quiet: enable non-verbose mode

Installing Secure Boot

* You need to boot in the freshly installed OS (without chroot) before following these steps.

Before you proceed, beware of this.

Secure Boot is a security feature found in the UEFI standard, designed to add a layer of protection to the pre-boot process: by maintaining a cryptographically signed list of binaries authorized or forbidden to run at boot, it helps in improving the confidence that the machine core boot components (boot manager, kernel, initramfs) haven't been tampered with.

  1. Clear existing keys and reset Secure Boot to Setup Mode on firmware settings.
  2. pacman -S sbctl
  3. sbctl status
Installed:    Sbctl is not installed
Setup Mode:   Enabled
Secure Boot:  Disabled
  1. sbctl create-keys
  2. sbctl enroll-keys -> sbctl status
Installed:    Sbctl is installed
Owner GUID:   xxx
Setup Mode:   Disabled
Secure Boot:  Disabled
  1. sbctl verify -> sbctl sign -s <file>
  2. sbctl list-files

Using TPM 2.0

Trusted Platform Module (TPM) is an international standard for a secure cryptoprocessor, which is a dedicated microprocessor designed to secure hardware by integrating cryptographic keys into devices.

Check for support:

cat /sys/class/tpm/tpm0/tpm_version_major

Install required packages for management:

pacman -S tpm2-tss tpm2-tools

List available TPMs:

systemd-cryptenroll --tpm2-device=list
PATH        DEVICE     DRIVER
/dev/tpmrm0 NTC0702:00 tpm_tis

Platform Configuration Registers (PCR) contain hashes that can be read at any time but can only be written via the extend operation, which depends on the previous hash value, thus making a sort of blockchain. They are intended to be used for platform hardware and software integrity checking between boots (e.g. protection against Evil Maid attack). They can be used to unlock encryption keys and proving that the correct OS was booted.

See Accessing PCR registers.

Enroll the key in the TPM and the LUKS volume and bind the key to PCRs 0 and 7:

systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=0,7 /dev/disk/by-partlabel/cryptswap
  • PCR0: Core System Firmware executable code (aka Firmware)
  • PCR7: Secure Boot State
New TPM2 token enrolled as key slot 1.

Test that the key can open the volume:

/usr/lib/systemd/systemd-cryptsetup attach swap /dev/disk/by-partlabel/cryptswap - tpm2-device=auto

Update /etc/crypttab to unlock the encrypted swap at boot:

# Configuration for encrypted block devices.

# <name>       <device>                                     <password>              <options>
swap           /dev/disk/by-partlabel/cryptswap             -                       tpm2-device=auto

Update kernel parameters (/boot/loader/entries/arch.conf) to use TPM for decryption:

[...] rd.luks.name=<SWAP-PARTITION-UUID>=swap rd.luks.options=<SWAP-PARTITION-UUID>=tpm2-device=auto resume=/dev/mapper/swap [...]

If you wish to remove LUKS keys from TPM: systemd-cryptenroll /dev/disk/by-partlabel/cryptswap --wipe-slot=tpm2

Post-installation

Set up a wireless netwok

wifi-menu
netctl list
netctl enable <profile>
netctl is-enabled <profile>

Create an user

useradd -G wheel -m orhun
passwd orhun
pacman -S sudo vi
visudo # uncomment "%wheel ALL=(ALL) ALL"

Update pacman mirrors

(this section needs review)

sudo pacman -S reflector
reflector --country Germany --age 12 --protocol https --sort rate --save /etc/pacman.d/mirrorlist
curl "https://archlinux.org/mirrorlist/?country=TR&protocol=http&protocol=https&ip_version=4" | sudo tee -a /etc/pacman.d/mirrorlist
sudo vim /etc/pacman.d/mirrorlist

Install an AUR helper

pacman -S git wget rust base-devel
rustup install stable
git clone https://aur.archlinux.org/paru
cd paru/
makepkg -si

Install display server

pacman -S xorg-server xorg-xinit xterm

Also, install xf86-video-amdgpu or xf86-video-intel based on CPU architecture respectively.

Install window manager

pacman -S i3

Configure i3 and run it with xinit.

Install code editor

pacman -S neovim

Install web browser

pacman -S firefox-developer-edition

Install docker

pacman -S docker
usermod -a -G docker orhun
systemctl enable --now docker.service

Set up screen locker

Install i3lock:

paru i3lock-fancy

Install screenshot utility:

pacman -S menyoki

Create a script at ~/scripts/lock.sh for locking the screen:

#!/usr/bin/env bash

i3lock-fancy -g -t "" -- menyoki -q cap --root png -c fast save 2>/dev/null

Lock the screen after 5 minutes of inactivity:

  1. Install the screen locker:
pacman -S xautolock
  1. Create /etc/systemd/system/screen-locker.service:
[Unit]
Description=Lock the screen automatically after a timeout

[Service]
Type=simple
User=orhun
Environment=DISPLAY=:0
ExecStart=/usr/bin/xautolock -time 5 -locker /home/orhun/scripts/lock.sh -detectsleep
Restart=on-failure
RestartSec=5m

[Install]
WantedBy=graphical.target

Lock the screen after suspend:

  1. Create /etc/systemd/system/resume-locker.service:
[Unit]
Description=Lock the screen on resume from suspend
Before=suspend.target

[Service]
Type=forking
User=orhun
Environment=DISPLAY=":0"
ExecStart=/usr/bin/bash /home/orhun/scripts/lock.sh

[Install]
WantedBy=suspend.target
WantedBy=sleep.target
  1. Keep the lock screen from flashing the desktop:

2.a. Create /lib/systemd/system-sleep/blank:

#!/usr/bin/env bash

if [ "$1" == "pre" ]; then
  sleep 2
fi

2.b. chmod +x /lib/systemd/system-sleep/blank

Lastly, start/enable both services:

systemctl enable --now screen-locker.service
systemctl enable --now resume-locker.service

Set up audio

Check the audio device:

lspci | grep -i audio

Install pipewire/pulse:

pacman -S alsa-utils pipewire pipewire-pulse
systemctl start --user pipewire-pulse.service
pactl info

Set up bluetooth:

rfkill unblock all
pacman -S bluez bluez-utils
systemctl start bluetooth.service
systemctl enable bluetooth.service

Update /etc/bluetooth/main.conf to auto power-on the bluetooth device after boot:

[Policy]
AutoEnable=true

Configure bluetooth headset:

bluetoothctl

[bluetooth]# power on
[CHG] Controller XX:XX:XX:XX:XX:XX Class: 0x006c010c
Changing power on succeeded
[CHG] Controller XX:XX:XX:XX:XX:XX Powered: yes

[bluetooth]# agent on
Agent is already registered
[bluetooth]# default-agent
Default agent request successful

[bluetooth]# scan on
Discovery started
[CHG] Controller XX:XX:XX:XX:XX:XX Discovering: yes
[NEW] Device E8:D0:3C:8B:7B:48 JBL TUNE500BT

[bluetooth]# pair E8:D0:3C:8B:7B:48 
Attempting to pair with E8:D0:3C:8B:7B:48
[CHG] Device E8:D0:3C:8B:7B:48 Connected: yes
[CHG] Device E8:D0:3C:8B:7B:48 ServicesResolved: yes
[CHG] Device E8:D0:3C:8B:7B:48 Paired: yes
Pairing successful
[CHG] Device E8:D0:3C:8B:7B:48 ServicesResolved: no
[CHG] Device E8:D0:3C:8B:7B:48 Connected: no

[bluetooth]# connect E8:D0:3C:8B:7B:48 
Attempting to connect to E8:D0:3C:8B:7B:48
[CHG] Device E8:D0:3C:8B:7B:48 Connected: yes
Connection successful
[CHG] Device E8:D0:3C:8B:7B:48 ServicesResolved: yes

[JBL TUNE500BT]# trust E8:D0:3C:8B:7B:48 
[CHG] Device E8:D0:3C:8B:7B:48 Trusted: yes
Changing E8:D0:3C:8B:7B:48 trust succeeded

[JBL TUNE500BT]# scan off
[JBL TUNE500BT]# exit

Update /etc/pulse/default.pa for auto connecting to the bluetooth headset:

### Automatically switch to newly-connected devices
load-module module-switch-on-connect

Change TrackPoint sensitivity

Install xinput for configuring devices:

pacman -S xorg-xinput xf86-input-libinput

List the available devices by running xinput command:

⎡ Virtual core pointer                    	id=2	[master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer              	id=4	[slave  pointer  (2)]
⎜   ↳ ETPS/2 Elantech Touchpad                	id=12	[slave  pointer  (2)]
⎜   ↳ ETPS/2 Elantech TrackPoint              	id=13	[slave  pointer  (2)]

List the properties of the TrackPoint:

xinput list-props "ETPS/2 Elantech TrackPoint"
[...]
libinput Accel Speed (316):	0.000000
libinput Accel Speed Default (317):	0.000000
libinput Accel Profiles Available (318):	1, 1
[...]

Override the libinput Accel Speed property in /etc/X11/xorg.conf.d/20-thinkpad.conf:

Section "InputClass"
    Identifier "TrackPoint Configuration"
    MatchProduct "ETPS/2 Elantech TrackPoint"
    Option "AccelSpeed"	"-0.65"
EndSection

References

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