Joining in the “by the way” club, finally.
Official Guide
Preparation
Download Arch ISO, create bootable USB using ventoy or rufus, disable Secure Boot, boot ISO.
Enlarge console font by running command "setfont ter-132b"
if needed.
The reflector didn’t work well for me, I had to pick mirror servers manually then wrote to the mirrorlist:
# cat /etc/pacman.d/mirrorlist <<EOB
Server = https://mirrors.aliyun.com/archlinux/\$repo/os/\$arch
Server = https://mirrors.tuna.tsinghua.edu.cn/archlinux/\$repo/os/\$arch
Server = https://mirrors.ustc.edu.cn/archlinux/\$repo/os/\$arch
EOB
Partition Disk
When using GPT, it is advised to follow the
Discoverable Partitions Specification
since systemd-gpt-auto-generator
can automount them. The EFI system partition, XBOOTLDR partition,
swap partition and home partition types can be changed using the set command,
while for the root partition and others, you will need to specify the partition type UUID manually with the type command.
Ref: Parted#Partition schemes
EFI system partition on a GUID Partition Table
is identified by the partition type GUID c12a7328-f81f-11d2-ba4b-00a0c93ec93b.
Parted can set it automatically, create a partition with fat32 as the file system type and set the esp flag on it.
Ref: EFI system partition#GPT partitioned disks,
Parted#UEFI/GPT examples
Root partition type GUID should be “root partition” not “LUKS partition”, which is
4f68bce3-e8cd-4db1-96e7-fbcaf984b709.
Ref: dm-crypt/Encrypt an entire system/Configuring the boot loader
Partition alignment need to be handled manually with parted.
Ref: Parted#Alignment
Disk file name would be like /dev/sda, /dev/nvme0n1, /dev/mmcblk0, /dev/vda.
Ref: Device file#Block devices
# parted /dev/vda
(parted) mklabel gpt
(parted) mkpart efip fat32 1MiB 1025MiB
(parted) set 1 esp on
(parted) mkpart rootp ext4 1025MiB 100%
(parted) type 2 4f68bce3-e8cd-4db1-96e7-fbcaf984b709
All partitions that have partition labels are listed in the /dev/disk/by-partlabel directory.
Ref: Persistent block device naming#by-partlabel
# ls -l /dev/disk/by-partlabel
total 0
lrwxrwxrwx 1 root root ... efip -> ../../vda1
lrwxrwxrwx 1 root root ... rootp -> ../../vda2
EFI Partition
Ref: EFI system partition#Format the partition
# mkfs.fat -F32 /dev/disk/by-partlabel/efip
LUKS
Ref:
dm-crypt/Device encryption#Formatting LUKS partitions ,
dm-crypt/Device encryption#Unlocking/Mapping LUKS partitions with the device mapper
Format LUKS partition and open:
# cryptsetup luksFormat /dev/disk/by-partlabel/rootp
# cryptsetup open /dev/disk/by-partlabel/rootp luksroot
# ls /dev/mapper/luksroot
Btrfs
Ref: Btrfs#File system on a single device , Btrfs#Subvolumes , Snapper#Suggested filesystem layout
Create Btrfs filesystem:
# mkfs.btrfs /dev/mapper/luksroot
# mount /dev/mapper/luksroot /mnt
# btrfs subvolume create /mnt/@
# btrfs subvolume create /mnt/@home
# btrfs subvolume create /mnt/@var
# btrfs subvolume create /mnt/@data
# umount /mnt
There’s a bit extra work needed to let @var subvolume work without issue, demonstrated at section Move PacmanDB of this post.
Mount Filesystem
Ref: Btrfs#Compression , EFI system partition#Typical mount points
# mount -o subvol=@ /dev/mapper/luksroot /mnt
# mount -o subvol=@home --mkdir /dev/mapper/luksroot /mnt/home
# mount -o subvol=@var --mkdir /dev/mapper/luksroot /mnt/var
# mount -o subvol=@data --mkdir /dev/mapper/luksroot /mnt/data
# mount --mkdir /dev/disk/by-partlabel/efip /mnt/efi
Install Base Pkgs
Ref: Installation guide#Install essential packages
Kernel
CPU microcode updates "amd-ucode"
or "intel-ucode"
for hardware bug and security fixes:
# pacstrap -K /mnt base linux linux-lts linux-firmware \
btrfs-progs amd-ucode
"-K"
means to initialize an empty pacman keyring in the target, so only adding it at first running.
Ref: pacstrap(8)
The latest kernel sometimes may cause annoying bugs like this, so setting LTS kernel as a fallback option would be a good choice.
Swap on Zram
Ref: Zram#Using zram-generator
# pacstrap /mnt zram-generator
Create "/mnt/etc/systemd/zram-generator.conf"
with:
[zram0]
zram-size = min(ram, 8192)
compression-algorithm = zstd
PipeWire
Ref: Advanced Linux Sound Architecture , PipeWire
# pacstrap /mnt alsa-utils \
pipewire wireplumber \
pipewire-alsa pipewire-pulse pipewire-jack lib32-pipewire
Sudo
Ref: Sudo#Environment variables , Sudo#Example entries , Sudo#Tips and tricks
# pacstrap /mnt sudo bash-completion
Create "/mnt/etc/sudoers.d/sudoers"
with:
%wheel ALL=(ALL:ALL) ALL
Defaults passwd_timeout = 0
Defaults timestamp_type = global
Defaults timestamp_timeout = 15
Defaults env_keep += "http_proxy https_proxy no_proxy"
Defaults editor = /usr/bin/nvim
Ref: Sudo#Passing aliases
# echo "alias sudo='sudo '" >> /mnt/etc/profile.d/bashrc
Neovim
# pacstrap /mnt neovim
# echo "EDITOR=/usr/bin/nvim" >> /mnt/etc/profile.d/bashrc
Plymouth
Ref: Plymouth
# pacstrap /mnt plymouth
# cat >> /mnt/etc/plymouth/plymouth.conf <<EOB
[Daemon]
Theme=spinner
EOB
Add plymouth to the HOOKS array, demonstrated at section Initramfs of this post.
Add "quiet"
"splash"
kernel parameters,
demonstrated at section Boot Loader of this post.
Console Font
# pacstrap /mnt terminus-font
# echo "FONT=ter-132b" >> /mnt/etc/vconsole.conf
Desktop Font
# pacstrap /mnt noto-fonts noto-fonts-cjk noto-fonts-emoji \
hicolor-icon-theme
Adjust fallback fonts order, this is for fixing wierd looking of some Chinese characters,
such as “复制”.
Ref: Font configuration#Fontconfig configuration
, Font configuration#Alias
Create "/etc/fonts/local.conf"
with:
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
<fontconfig>
<alias>
<family>sans-serif</family>
<prefer>
<family>Noto Sans</family>
<family>Noto Sans CJK SC</family>
<family>Noto Sans CJK TC</family>
<family>Noto Sans CJK HK</family>
<family>Noto Sans CJK JP</family>
<family>Noto Sans CJK KR</family>
</prefer>
</alias>
<alias>
<family>serif</family>
<prefer>
<family>Noto Serif</family>
<family>Noto Serif CJK SC</family>
<family>Noto Serif CJK TC</family>
<family>Noto Serif CJK HK</family>
<family>Noto Serif CJK JP</family>
<family>Noto Serif CJK KR</family>
</prefer>
</alias>
<alias>
<family>monospace</family>
<prefer>
<family>Noto Sans Mono</family>
<family>Noto Sans Mono CJK SC</family>
<family>Noto Sans Mono CJK TC</family>
<family>Noto Sans Mono CJK HK</family>
<family>Noto Sans Mono CJK JP</family>
<family>Noto Sans Mono CJK KR</family>
</prefer>
</alias>
</fontconfig>
Utilities
# pacstrap /mnt \
base-devel pacman-contrib \
man-db man-pages texinfo \
iwd git rsync
Ref: iwd
Fstab
When using encrypted containers with dm-crypt, the labels of filesystems inside of
containers are not available while the container is locked/encrypted.
Ref: Persistent block device naming#by-label
The advantage of using the UUID method is that it is much less likely that name collisions occur than with labels.
Further, it is generated automatically on creation of the filesystem.
It will, for example, stay unique even if the device is plugged into another system
(which may perhaps have a device with the same label).
Ref: Persistent block device naming#by-uuid
It is preferable to mount using subvol=/path/to/subvolume, rather than the subvolid,
as the subvolid may change when restoring snapshots, requiring a change of mount configuration.
Ref: Btrfs#Mounting subvolumes
Since "genfstab"
would generate subvolid and other redundant options, I choose to write fstab manually.
Save partitions UUID to temp files for later use:
# blkid -s UUID -o value /dev/vda1 > /tmp/efiuuid
# blkid -s UUID -o value /dev/mapper/luksroot > /tmp/luksuuid
Edit "/mnt/etc/fstab"
with:
UUID=XXXX-XXXX /efi vfat defaults 0 2
UUID=xxxxxxxx-...-xxxxxxxxxxxx / btrfs compress=zstd,subvol=/@ 0 0
UUID=xxxxxxxx-...-xxxxxxxxxxxx /home btrfs compress=zstd,subvol=/@home 0 0
UUID=xxxxxxxx-...-xxxxxxxxxxxx /var btrfs compress=zstd,subvol=/@var 0 0
UUID=xxxxxxxx-...-xxxxxxxxxxxx /data btrfs compress=zstd,subvol=/@data 0 0
Disable Watchdogs
# cat > /mnt/etc/modprobe.d/nowatchdogs.conf <<EOB
blacklist iTCO_wdt
blacklist sp5100_tco
EOB
Ref: Improving performance#Watchdogs , Kernel module#Blacklisting
Systemd-networkd
# mkdir -p /mnt/etc/systemd/system/systemd-networkd-wait-online.service.d
# cd /mnt/etc/systemd/system/systemd-networkd-wait-online.service.d
# cat > wait-for-only-one-interface.conf <<EOB
[Service]
ExecStart=
ExecStart=/usr/lib/systemd/systemd-networkd-wait-online --any
EOB
# cd -
# cat > /mnt/etc/systemd/network/23-wired.network <<EOB
[Match]
Type=ether
Kind=!*
[Link]
RequiredForOnline=routable
[Network]
DHCP=yes
[DHCPv4]
RouteMetric=100
[IPV6AcceptRA]
RouteMetric=100
EOB
# cat > /mnt/etc/systemd/network/27-wireless.network <<EOB
[Match]
Type=wlan
[Link]
RequiredForOnline=routable
[Network]
DHCP=yes
IgnoreCarrierLoss=3s
[DHCPv4]
RouteMetric=600
[IPV6AcceptRA]
RouteMetric=600
EOB
# sed -i '/^\[Network/a\ManageForeignRoutingPolicyRules=no' \
/mnt/etc/systemd/networkd.conf
# systemctl enable systemd-networkd --root=/mnt
Ref: Systemd-networkd , WireGuard#Connection lost after sleep using systemd-networkd
Chroot
# arch-chroot /mnt
Time:
# ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# hwclock --systohc
Localization:
# echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen
# echo "zh_CN.UTF-8 UTF-8" >> /etc/locale.gen
# locale-gen
# echo "LANG=en_US.UTF-8" >> /etc/locale.conf
Hostname:
# echo "archlinux" >> /etc/hostname
Remap CapsLock to Control for console.
Ref: Linux console/Keyboard configuration#Creating a custom keymap
# _kmapdir=/mnt/usr/share/kbd/keymaps/i386/qwerty
# gzip -dc < ${_kmapdir}/us.map.gz > ${_kmapdir}/usa.map
# sed -i '/^keycode[[:space:]]58/c\keycode 58 = Control' \
${_kmapdir}/usa.map
# echo "KEYMAP=usa" >> /mnt/etc/vconsole.conf
Enable multilib repo. Ref: General recommendations#Repositories
# cat >> /mnt/etc/pacman.conf <<EOB
[multilib]
Include = /etc/pacman.d/mirrorlist
EOB
Enable BBR. Ref: Sysctl#Enable BBR
# cat > /mnt/etc/sysctl.d/77-sysctl.conf << EOB
net.core.default_qdisc = cake
net.ipv4.tcp_congestion_control
EOB
Root Password:
# passwd
Create User:
# useradd -m -G wheel -s /bin/bash user1
# passwd user1
Initramfs
Ref: dm-crypt/System configuration#mkinitcpio
Edit "/etc/mkinitcpio.conf"
:
HOOKS=(base systemd plymouth autodetect microcode modconf kms keyboard sd-vconsole sd-encrypt block filesystems fsck)
Recreate initramfs image:
# mkinitcpio -P
Systemd-boot
Install UEFI boot manager.
Ref: Systemd-boot#Installing the UEFI boot manager
, Systemd-boot#systemd service
bootctl install
systemctl enable systemd-boot-update.service
Boot Files
Copy boot files to ESP.
Ref: EFI system partition#Alternative mount points
# mkdir -p /efi/EFI/arch
# cp -a /boot/vmlinuz-linux /efi/EFI/arch/
# cp -a /boot/initramfs-linux.img /efi/EFI/arch/
# cp -a /boot/initramfs-linux-fallback.img /efi/EFI/arch/
# cp -a /boot/vmlinuz-linux-lts /efi/EFI/arch/
# cp -a /boot/initramfs-linux-lts.img /efi/EFI/arch/
# cp -a /boot/initramfs-linux-lts-fallback.img /efi/EFI/arch/
Auto update boot files under ESP with systemd.
Ref: EFI system partition#Using systemd
, systemd.path(5)
Create "/etc/systemd/system/efistub-update.path"
[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"
[Unit]
Description=Copy EFISTUB Kernel to EFI system partition
[Service]
Type=oneshot
ExecStart=/usr/bin/cp -af /boot/vmlinuz-linux /efi/EFI/arch/
ExecStart=/usr/bin/cp -af /boot/initramfs-linux.img /efi/EFI/arch/
ExecStart=/usr/bin/cp -af /boot/initramfs-linux-fallback.img /efi/EFI/arch/
ExecStart=/usr/bin/cp -af /boot/vmlinuz-linux-lts /efi/EFI/arch/
ExecStart=/usr/bin/cp -af /boot/initramfs-linux-lts.img /efi/EFI/arch/
ExecStart=/usr/bin/cp -af /boot/initramfs-linux-lts-fallback.img /efi/EFI/arch/
Enable systemd units:
# systemctl enable efistub-update.{path,service}
Boot Loader
Ref: Systemd-boot#Configuration
Edit "/efi/loader/loader.conf"
:
default arch.conf
timeout 0
console-mode max
editor no
"timeout 0"
means not showing menu and boot immediately.
Create "/efi/loader/entries/arch.conf"
.
title Arch Linux
linux /EFI/arch/vmlinuz-linux
initrd /EFI/arch/initramfs-linux.img
options rootflags=subvol=@ quiet splash
To use a subvolume as the root mountpoint, specify the subvolume via a kernel parameter
using rootflags=subvol=@. Or you would get an error “Failed to start Switch Root” when booting.
Ref: Btrfs#Mounting subvolume as root
Create "/efi/loader/entries/arch-lts.conf"
.
title Arch Linux LTS
linux /EFI/arch/vmlinuz-linux-lts
initrd /EFI/arch/initramfs-linux-lts.img
options rootflags=subvol=@ quiet splash
Create "/efi/loader/entries/arch-fallback.conf"
.
title Arch Linux (fallback initramfs)
linux /EFI/arch/vmlinuz-linux
initrd /EFI/arch/initramfs-linux-fallback.img
options rootflags=subvol=@
Note: If disk partitions were not following
Discoverable Partitions Specification
, which means root partition would not be discovered and auto mounted, booting system would stuck at
"a start job is running for /dev/gpt-auto-root"
and timeout. To fix this, specify root partition in kernel parameters.
Ref: dm-crypt/Encrypting an entire system#Configuring the boot loader,
dm-crypt/System configuration#rd.luks.name
options rd.luks.name=<UUID>=luskroot root=/dev/mapper/luksroot rootflags=subvol=@ quiet
Move PacmanDB
The pacman database in /var/lib/pacman must stay on the root subvolume @
.
Ref: Snapper#Suggested filesystem layout
So, to keep /var as a separate btrfs subvolume, we need to move pacman database out of /var:
# sed -i '/^#DBPath/a\DBPath=/usr/pacman' /etc/pacman.conf
# mv /var/lib/pacman /usr/pacman
Reboot
# exit
# reboot
In case you’ve lost track of the installation process and want to start over, here’s
some commands that can help you reset disk state, then you can retry installation.
Ref: dm-crypt/Drive preparation#Wipe LUKS header
# umount /mnt/efi
# umount -AR /mnt
# cryptsetup close /dev/mapper/luksroot
# cryptsetup erase /dev/vda2
# wipefs -a /dev/vda