Arch Linux install guide 2022 Edition
Posted on Fri 24 December 2021 in software
Introduction
This is the way I usually install Arch Linux. It is heavily based on systemd services to avoid the installation of additional software. Use it as inspiration for your own custom install.
Arch Linux is all about freedom of choice so these are the choices I made:
Component | Implementation |
---|---|
Kernel | Default linux |
Partition layout | GPT |
Bootloader | systemd-boot |
Initramfs | systemd based mkinitcpio |
Partitioning | Primary partitions, single partition for root and home |
Encryption | LUKS2 for swap and rootfs |
Root filesystem | Ext4 |
Swap space | Dedicated partition |
Network manager | systemd-networkd |
Wifi | wpa_supplicant |
Mobile broadband | Custom modem-manager script |
Name resolution | systemd-resolved |
Network Time | systemd-timesyncd |
Text Editor | Neovim (nvim ) |
User shell | fish |
/bin/sh Shell |
dash |
Privilege excalation | sudo |
Desktop Environment | xfce |
Window Manager | i3 |
Terminal | xfce-terminal |
Keyboard layout | en-us international with AtlGr dead keys; caps lock as compose key |
Explanation for code examples:
# command executed as root
$ command executed as unprivileged user
% command executed inside chroot as root
Assumptions
- You install to a notebook or desktop computer (ignore battery related things)
- You install to an NVME drive
- You read through my commands carefully and understand what they do before blindly pasting them into your machine
- I’m not responsible for anything you do
With that out of the way, let’s get started!
Installation
Partition disks
Create 3 primary partitions for:
- ESP: 1GB, FAT32
- Swap:
- With hibernation support: same as RAM size
- Without: ~2-8GB depending on the use case of the machine
- RootFS: Rest of your disk
# cfdisk -z /dev/nvme0n1
# mkdosfs -F 32 -n ESP /dev/nvme0n1p1
# cryptsetup LuksFormat --type luks2 --label CRYPTSWAP /dev/nvme0n1p2
# cryptsetup LuksFormat --type luks2 --label CRYPTROOT /dev/nvme0n1p3
# cryptsetup open --allow-discards --perf-no_read_workqueue --perf-no_write_workqueue --persistent --type luks2 /dev/nvme0n1p2 cryptswap
# cryptsetup open --allow-discards --perf-no_read_workqueue --perf-no_write_workqueue --persistent --type luks2 /dev/nvme0n1p3 cryptroot
# mkswap -L SWAP /dev/mapper/cryptswap
# mkfs.ext4 -L ROOT -O metadata_csum /dev/mapper/cryptroot
# mount /dev/mapper/cryptroot /mnt -o noatime,discard
# mkdir /mnt/boot
# mount /dev/nvme0n1p1 /mnt/boot -o noatime,discard
# swapon -d /dev/mapper/cryptswap
Final result should look like this:
# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
nvme0n1 259:0 0 953.9G 0 disk
├─nvme0n1p1 259:1 0 1G 0 part /boot
├─nvme0n1p2 259:2 0 32G 0 part
│ └─cryptswap 254:1 0 32G 0 crypt [SWAP]
└─nvme0n1p3 259:3 0 920.9G 0 part
└─cryptroot 254:0 0 920.9G 0 crypt /
Install base system
Some packages mentioned here depend on your hardware
# pacstrap /mnt base base-devel linux linux-firmware (intel-ucode|amd-ucode) [sof-firmware] neovim man-db man-pages texinfo
Generate fstab
# genfstab -U /mnt >> /mnt/etc/fstab
Setup bootloader
Get UUIDs of drives:
# blkid
/dev/nvme0n1p1: LABEL_FATBOOT="ESP" LABEL="ESP" UUID="1234-0001" BLOCK_SIZE="512" TYPE="vfat" PARTUUID="deadbeef-1234-5678-90ab-10000001"
/dev/nvme0n1p2: UUID="deadbeef-1234-5678-90ab-00000002" LABEL="CRYPTSWAP" TYPE="crypto_LUKS" PARTUUID="deadbeef-1234-5678-90ab-10000002"
/dev/nvme0n1p3: UUID="deadbeef-1234-5678-90ab-00000003" LABEL="CRYPTROOT" TYPE="crypto_LUKS" PARTUUID="deadbeef-1234-5678-90ab-20000003"
/dev/mapper/cryptswap: LABEL="SWAP" UUID="deadbeef-1234-5678-90ab-20000002" TYPE="swap"
/dev/mapper/cryptroot: LABEL="ROOT" UUID="deadbeef-1234-5678-90ab-20000003" BLOCK_SIZE="4096" TYPE="ext4"
Install and configure systemd-boot
:
# arch-chroot /mnt # we'll stay in chroot for a while so I'll not prefix every code block with that
% bootctl install
% nvim /boot/loader/loader.conf
default arch.conf
timeout 3
console-mode keep
editor yes
auto-entries
auto-firmware
Setup boot entries:
% nvim /boot/loader/entries/arch.conf
title Arch Linux
linux /vmlinuz-linux
initrd /intel-ucode.img
initrd /initramfs-linux.img
options root="UUID=deadbeef-1234-5678-90ab-20000003" resume="UUID=deadbeef-1234-5678-90ab-20000002" rd.luks.name=deadbeef-1234-5678-90ab-00000003=cryptroot rd.luks.name=deadbeef-1234-5678-90ab-00000002=cryptswap rd.luks.options=discard rw
% nvim /boot/loader/entries/arch-fallback.conf
title Arch Linux (fallback initramfs)
linux /vmlinuz-linux
initrd /intel-ucode.img
initrd /initramfs-linux-fallback.img
options root="UUID=deadbeef-1234-5678-90ab-20000003" resume="UUID=deadbeef-1234-5678-90ab-20000002" rd.luks.name=deadbeef-1234-5678-90ab-00000003=cryptroot rd.luks.name=deadbeef-1234-5678-90ab-00000002=cryptswap rd.luks.options=discard rw
Setup vconsole
% nvim /etc/vconsole.conf
KEYMAP=us
FONT=lat2-16
FONT_MAP=8859-2
Setup initramfs
Switching to systemd
based initramfs:
% nvim /etc/mkinitcpio.conf
[...]
HOOKS=(base systemd autodetect keyboard sd-vconsole modconf block sd-encrypt filesystems fsck)
[...]
% mkinitcpio -P
Setup networking
Setup for wired connections:
% nvim /etc/systemd/network/wired.network
[Match]
Name=enp*
[Network]
DHCP=yes
MulticastDNS=resolve
DNSSEC=allow-downgrade
[DHCP]
RouteMetric=10
Setup for wireless connections:
% nvim /etc/systemd/network/wireless.network
[Match]
Name=wlp*
[Network]
DHCP=yes
MulticastDNS=resolve
DNSSEC=allow-downgrade
IPv6PrivacyExtensions=kernel
[DHCP]
RouteMetric=20
Enable IPv6 privacy extensions:
Execute this first:
% sysctl net.ipv6.conf.wlp3s0.addr_gen_mode=3
% ip link set wlp3s0 down
% ip link set wlp3s0 up
% sysctl net.ipv6.conf.wlp3s0.stable_secret
Take the secret from the last command and put it here:
% nvim /etc/sysctl.d/40-ipv6.conf
# Enable IPv6 Privacy Extensions
net.ipv6.conf.all.use_tempaddr = 2
net.ipv6.conf.default.use_tempaddr = 2
net.ipv6.conf.wlp3s0.use_tempaddr = 2
net.ipv6.conf.enp5s0.use_tempaddr = 2
# Enable IPv6 stable privacy mode
net.ipv6.conf.wlp3s0.stable_secret = 25a3:36e6:9384:1111:9866:def1:abcd:1234
net.ipv6.conf.wlp3s0.addr_gen_mode = 2
Install additional packages for wifi and enable daemon on your wifi interface:
$ yay -S wpa_supplicant
# systemdctl enable wpa_supplicant@wlp3s0.service
Setup for mobile broadband follows later.
% systemctl enable systemd-networkd
% systemctl enable systemd-resolved
% rm /etc/resolv.conf
% ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
The last command will break your DNS but that’s fine because we will reboot in a moment. Maybe you have to do this after reboot. Definitly check if it worked.
Set hostname
% echo "myhostname" > /etc/hostname
Setup network time and timezone
% nvim /etc/systemd/timesyncd.conf
[Time]
NTP=0.arch.pool.ntp.org 1.arch.pool.ntp.org 2.arch.pool.ntp.org 3.arch.pool.ntp.org
FallbackNTP=0.de.pool.ntp.org 1.de.pool.ntp.org 2.de.pool.ntp.org 3.de.pool.ntp.org
% systemctl enable systemd-timesyncd
% ln -sf /usr/share/zoneinfo/Europe/Berlin /etc/localtime
% hwclock --systohc
Locale setup
Edit /etc/locale.gen
file in your chroot and uncomment en_US.UTF-8 UTF-8
locales. Then run:
% locale-gen
% nvim /etc/locale.conf
LANG=en_US.UTF-8
LANGUAGE=en_US:en
LC_COLLATE=C
Set root password
% passwd
Reboot into new system
% exit # exit chroot
# umount -R /mnt
# swapoff -a
# cryptsetup close cryptroot
# cryptsetup close cryptswap
# reboot
Check if time is correct
# timedatectl status
Local time: Thu 2021-08-05 18:08:59 CEST
Universal time: Thu 2021-08-05 16:08:59 UTC
RTC time: Thu 2021-08-05 16:09:09
Time zone: Europe/Berlin (CEST, +0200)
System clock synchronized: no
NTP service: inactive
RTC in local TZ: no
Enable synchronisation with:
# timedatectl set-ntp true
Create unprivileged user
# pacman -Syu sudo fish python pkgfile
# useradd -m -G wheel -s /usr/bin/fish bob
# EDITOR=nvim visudo
[...]
%wheel ALL=(ALL) ALL
[...]
# passwd bob
Setup AUR
Use unprivileged user from here on
$ sudo pacman -S git
$ git clone https://aur.archlinux.org/yay.git
$ cd yay
$ makepkg -csi
$ cd ..
$ rm -fr yay
Some quality of live things
Update systemd-boot on ESP when systemd is updated
$ yay -S systemd-boot-pacman-hook
System monitoring with temperatures
$ yay -S htop lsof strace lm_sensors
# sensors-detect # hit enter until it stops
Use dash
for /bin/sh
This could cause problems, use checkbashisms
to check your scripts:
$ yay -S checkbashisms
$ find /usr/bin/ -type f -perm -o=r -print0 | xargs -0 gawk '/^#!.*( |[/])sh/{printf "%s\0", FILENAME} {nextfile}' | xargs -0 checkbashisms
$ yay -S dashbinsh
Make pacman nice and fast
Edit /etc/pacman.conf
and add/change these lines:
Color
VerbosePkgLists
ParallelDownloads = 10
ILoveCandy
Also enable multilib:
[multilib]
Include = /etc/pacman.d/mirrorlist
Grafical setup
Setup gdm
$ yay -S gdm
# systemctl enable gdm.service
Setup XFCE with i3 as window manager
Install packages first. Choose as many from these groups as you like. You can probably skip most panel plugins:
$ yay -S xfce4 xfce4-goodies
My favorites even under i3 are: xfce4-screenshooter
, xfce4-terminal
, thunar
For thunar
setup gvfs
:
$ yay -S gvfs gvfs-afc gvfs-goa gvfs-google gvfs-gphoto2 gvfs-mtp gvfs-nfs gvfs-smb
Install i3 (or i3-gaps if you wanna waste precious space just for looks):
$ yay -S i3 i3blocks j4-dmenu-desktop
Switch to i3 as window manager:
xfconf-query -c xfce4-session -p /sessions/Failsafe/Client0_Command -t string -sa xfsettingsd
xfconf-query -c xfce4-session -p /sessions/Failsafe/Client1_Command -t string -sa i3
This should change the value from xfwm4
to i3
in ~/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-session.xml
.
Fonts
% yay -S ttf-droid ttf-dejavu \ # default stuff
noto-fonts noto-fonts-cjk noto-fonts-emoji noto-fonts-extra \ # emoji
adobe-source-code-pro-fonts \ # monospace
adobe-source-sans-fonts \ # sans-serif
adobe-source-han-sans-cn-fonts adobe-source-han-sans-tw-fonts adobe-source-han-serif-cn-fonts adobe-source-han-serif-tw-fonts \ # chinese
adobe-source-han-sans-jp-fonts adobe-source-han-serif-jp-fonts \ # japanese
adobe-source-han-sans-kr-fonts # korean
Bonus!
Optimize pacman/yay
$ yay -S ccache
In /etc/makepkg.conf
:
- For
CFLAGS
change-march=native
and-mtune=native
. - Set
MAKEFLAGS="-j8"
or any othe rnumber of cores you want to use - For
BUILDENV
enableccache
Wayland
Enable wayland support for Qt5/6
$ yay -S qt5-wayland qt6-wayland glfw-wayland
Enable wayland support for electron apps by editing ~/.config/electron-flags.conf
:
--enable-features=UseOzonePlatform
--ozone-platform=wayland
Install XWayland to support X11 applications:
$ yay -S xorg-xwayland
Sway
TBC
yay -S sway \
xdg-desktop-portal xdg-desktop-portal-wlr \ # screen sharing/webrtc
Gnome
Simply install the gnome group which includes most gnome packages you’ll need:
$ yay -S gnome gnome-tweaks webp-pixbuf-loader
After a few hundred lines of things scroll by this the stuff that was too fast to read:
Install these packages that add features you propably want:
$ yay -S qt5-svg \ # svg icon set support
vulkan-mesa-layers \ # vulkan support
vulkan-intel \ # vulkan support (intel)
gst-libav gst-plugins-ugly \ # media file support
intel-media-driver libva-intel-driver \ # media file support (intel)
eog-plugins \ # image support for eye of gnome
poppler-data \ # pdf feature support
p7zip unrar \ # file-roller archive support
gedit-plugins \
fwupd dmidecode \ # firmware update support
pipewire-alsa pipewire-pulse pipewire-zeroconf \ # pulseaudio replacement
xdg-desktop-portal xdg-desktop-portal-gtk \ # screen sharing/webrtc
gtk-engines \ # gtk2 themes
chromium \ # browser
evolution evolution-ews highlight \ # email client
Enable pipewire support in chromium by enabling: chrome://flags/#enable-webrtc-pipewire-capturer