When I was getting started with Arch linux, I quickly learned that there were a lot of tricky parts that no amount of studying the installation guide could get me through. I ran into a lot of problems that I could only sort through by reading other people’s system writups.
I just ran through a complete system rebuild today and figured it was time to do my own writup.
Live USB
Create and boot from an Arch live USB.
SSH (Optional)
If you have another system you can SSH in from, it’ll allow you to copy/paste commands.
Create a password for the root user on the live USB
passwd
Enable the ssh service
systemctl start sshd.service
You can find the ip address of the system:
ip addr show
The output can be a bit verbose. You can try to narrow it down by piping to grep.
ip addr show | grep "state UP"
Use that ip address to ssh in from a different system:
ssh root@<ip-address-you-found>
Check the Boot Mode
cat /sys/firmware/efi/fw_platform_size
For my system, the output is 64
, which indicates that the system is in UEFI mode in 64-bit.
A 32
would indicate UEFI mode in 32-bit.
If the output is anything else, you’ve got to go messing with your motherboard.
Create the Partitions
List Disks and Partitions
To identify the disk(s) you want to use during the installation:
lsblk
Example output:
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sdb 8:0 0 465.8G 0 disk
sda 8:16 0 9.1T 0 disk
For our purposes, let’s use sdb
as the target disk.
Create the Partitions
Using gdisk
for partitioning.
gdisk /dev/sdb
Create 3 partitions:
- Partition 1 - Code EA00 - XBOOTLDR partition - 512MB
- Partition 2 - Code EF00 - EFI System Partition - 256MB
- Partition 3 - Code 8309 - Linux LUKS - All the remaining space
Since gdisk
is interactive, I have to show this awkward collection of key presses.
Each use of [Enter]
below indicates that I’m taking the default value.
# Create a new GUID Partition Table (GPT)
o
Y
# Create the XBOOTLDR partition
n
[Enter]
0
+512M
ea00
# Create the EFI partition
n
[Enter]
[Enter]
+256M
ef00
# Create the LUKS partition
n
[Enter]
[Enter]
[Enter]
8309
# Persist the changes
w
Y
Setup LUKS
Use luks to encrypt and open the 3rd partition:
cryptsetup luksFormat \
--use-random \
-S 1 \
-s 512 \
-h sha512 \
-i 5000 \
/dev/sdb3
cryptsetup open /dev/sdb3 cryptlvm
Setup Volumes
First, create the physical volume.
I use the name cryptlvm
, but the name is arbitrary.
pvcreate /dev/mapper/cryptlvm
Create a volume group:
vgcreate vg /dev/mapper/cryptlvm
Now create logical volumes for swap, root, and home.
Use the appropriate amount of space for root, which is where installed packages will live by default. 128G is enough for me right now, but for you it may be too small.
lvcreate -L 8G vg -n swap
lvcreate -L 128G vg -n root
lvcreate -l 100%FREE vg -n home
NOTE the case-sensitivity of arguments. The ‘-l’ is not a typo for ‘-L’.
Format the Partitions
Using FAT32 for the efi and boot partitions - they need to be readable by the firmware.
mkfs.fat -F32 /dev/sdb1
mkfs.fat -F32 /dev/sdb2
Use the old reliable ext4 for root and home.
mkfs.ext4 /dev/vg/root
mkfs.ext4 /dev/vg/home
mkswap /dev/vg/swap
Mounting
Mount the root partition.
mount /dev/vg/root /mnt
Create the nested mount points.
mkdir /mnt/home
mkdir /mnt/boot
mkdir /mnt/efi
And mounting
mount /dev/vg/home /mnt/home
mount /dev/sdb1 /mnt/boot
mount /dev/sdb2 /mnt/efi
swapon /dev/vg/swap
At this point, lsblk
should produce output that looks similar to this:
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sdb 8:0 0 465.8G 0 disk
├─sdb1 8:1 0 512M 0 part /boot
├─sdb2 8:2 0 256M 0 part /efi
└─sdb3 8:3 0 465.2G 0 part
└─cryptlvm 254:0 0 465.2G 0 crypt
├─vg-swap 254:1 0 8G 0 lvm [SWAP]
├─vg-root 254:2 0 128G 0 lvm /
└─vg-home 254:3 0 329.2G 0 lvm /home
Setup Initial Installation
Packages
Alter the mirror list, if you have any preferences.
vim /etc/pacman.d/mirrorlist
Install any essential programs.
pacman -Sy archlinux-keyring
pacstrap /mnt \
base \
linux \
linux-firmware \
base-devel \
git \
sudo \
archlinux-keyring \
lvm2 \
mkinitcpio \
vim \
dhcpcd \
openssh
Configure fstab
This will copy your current setup for all the mounted volumes/partitions/etc and save it to fstab so that it can be setup automatically on boot.
genfstab -U /mnt >> /mnt/etc/fstab
Chroot Into the Installation
arch-chroot /mnt
Update Root Password
passwd
Create User and Basic Configuration
Create a user and set the password.
useradd -m matt
passwd matt
Add the user to the wheel
group, which will determine who has access to sudo
.
gpasswd -a matt wheel
Run visudo
, which will open a file where you can add wheel users to sudoers. Uncomment this relevant section:
## Uncomment to allow members of group wheel to execute any command
%wheel ALL=(ALL) ALL
Setting the Clock
timedatectl set-ntp true
Adjust to your own time zone as-needed.
ln -sf /usr/share/zoneinfo/America/Denver /etc/localtime
hwclock --systohc
Locale
Uncomment en_US.UTF-8 UTF-8
in /etc/locale.gen
(or whatever line applies to you) and generate locale:
locale-gen
And similar for locale configuration:
echo "LANG=en_US.UTF-8" >> /etc/locale.conf
Networking
echo "myhostname" >> /etc/hostname
Update /etc/hosts
127.0.0.1 localhost
::1 ip6-localhost
127.0.1.1 myhostname.localdomain myhostname
Enable dhcpcd and ssh so everything works on the system’s first reboot
systemctl enable dhcpcd
systemctl enable sshd
.local Hostname Resolution
I have a ton of machines on my local network that I need to access on a regular basis. Local hostname resolution helps avoid hardcoding IP addresses everywhere.
Setup local hostname resolution with Avahi.
pacman -Sy avahi nss-mdns
Update hosts in /etc/nsswitch.conf
to add mdns.
The main thing is to make sure mdns_minimal [NOTFOUND=return]
gets added somewhere between files
and dns
.
Resolution will check sources in order.
We don’t want it querying dns for local requests.
hosts: mymachines resolve [!UNAVAIL=return] files myhostname mdns_minimal [NOTFOUND=return] dns
note that myhostname
and mymachines
are actual values, not placeholders
Enable avahi
systemctl enable avahi-daemon
Initramfs
Create a Keyfile
A keyfile lets us bypass unnecessary passwords on boot. Create one and add it as a LUKS key.
mkdir /root/secrets
chmod 700 /root/secrets
head -c 64 /dev/urandom > /root/secrets/crypto_keyfile.bin
chmod 600 /root/secrets/crypto_keyfile.bin
cryptsetup -v luksAddKey -i 1 /dev/sdb3 /root/secrets/crypto_keyfile.bin
Find the partition’s UUID value (and keep it on hand, we need it a few times). It will be one of these:
blkid | grep crypto_LUKS
Add this info to /etc/crypttab
:
cryptlvm UUID=<YOUR UUID> /root/secrets/crypto_keyfile.bin luks
Update mkinitcpio
We need to modify /etc/mkinitcpio.conf
and add some hooks.
lvm2 is required since this enables the initramfs to properly manage LVM volumes during the boot process.
encrypt is required since we’re using LUKS.
filesystems is required for ext4, but should already be there.
There’s a section for HOOKS, which should end up looking similar to this:
HOOKS=(base udev autodetect keyboard modconf block encrypt lvm2 filesystems fsck)
Create the initramfs Image
mkinitcpio -p linux
Add Microcode Support
You can check your processor with
lscpu
Based on the results, install either amd-ucode
or intel-ucode
pacman -S <your-ucode-type>
Note this value, which is used in the bootctl configuration, below.
Configure the Bootloader
So far I prefer systemd-boot to GRUB, which I was never able to get to cooperate with SecureBoot or LUKS2.
Create an entry at /boot/loader/entries/arch.conf
:
title Arch Linux
linux /vmlinuz-linux
initrd /<YOUR-UCODE-TYPE>.img
initrd /initramfs-linux.img
options cryptdevice=UUID=<UUID-OF-ROOT-PARTITION>:cryptlvm root=/dev/vg/root rw cryptkey=rootfs:/root/secrets/crypto_keyfile.bin
Configure /efi/loader/loader.conf
:
default arch.conf
timeout 5
console-mode max
editor no
You may want a lower timeout value; it dictates how many seconds the loader selection screen shows on boot.
Sanity Check
Run bootctl
with no params.
It should tell you if your configuration is obviously broken.
Restart the System
Exit chroot and reboot.
exit
umount -a /mnt
reboot
The new installation should be able to boot via systemd-boot without the live usb.
Secure Boot
Boot up normally without the live USB.
Run as root:
sudo su
Check the Current Status
Install sbctl:
pacman -S sbctl
Check if everything is ready by running:
sbctl status
These are the states we’re looking for. Setup mode, no secure boot, sbctl installed.
Installed: ✓ sbctl is installed
Setup Mode: ✗ Enabled
Secure Boot: ✗ Disabled
This can still go fine if sbctl doesn’t realize that its installed.
Disable Secure Boot and Enter Setup Mode
If the status isn’t what we want, we need to update the firmware settings.
systemctl reboot --firmware
When your system boots into the firmware, disable secure boot and enable setup mode/remove existing keys.
Unfortunately some motherboards make this quite hard to find.
You’ll want to set your UEFI firmware supervisor (administrator) password in the firmware settings; that way an attacker can’t simply boot into UEFI setup utility and turn off SecureBoot.
Don’t use the same UEFI firmware supervisor password as your encryption password for LUKS. On some old systems, the supervisor password can be recovered as plaintext from the EEPROM chip.
Restart.
Enroll the Keys
When you’re booted back into the new system:
sbctl create-keys
Enroll the keys
sbctl enroll-keys -m
Assuming that went well, we need to sign certain EFI files.
To identify the files we need to sign, we use sbctl verify
.
The lazy way I use:
sbctl verify | grep '✗' | cut -d ' ' -f 2 | xargs -n 1 sbctl sign -s
Need to sign these as well.
sbctl sign -s /boot/vmlinuz-linux
sbctl sign -s \
-o /usr/lib/systemd/boot/efi/systemd-bootx64.efi.signed \
/usr/lib/systemd/boot/efi/systemd-bootx64.efi
Run sbctl verify
again to ensure everything is kosher.
$ sbctl verify
Verifying file database and EFI images in /efi...
✓ /boot/vmlinuz-linux is signed
✓ /efi/EFI/BOOT/BOOTX64.EFI is signed
✓ /efi/EFI/systemd/systemd-bootx64.efi is signed
✓ /usr/lib/systemd/boot/efi/systemd-bootx64.efi.signed is signed
Turn on SecureBoot
Back to firmware settings.
systemctl reboot --firmware
Turn on Secure Boot in the settings and save. If all is well, your system should boot successfully.
Check if Secure Boot Worked
Now to check if everything worked out.
sbctl status
can help:
$ sbctl status
Installed: ✓ sbctl is installed
Owner GUID: <some-guid>
Setup Mode: ✓ Disabled
Secure Boot: ✓ Enabled
Vendor Keys: microsoft
And we can check the efi variable:
od -An -t u1 /sys/firmware/efi/efivars/SecureBoot-<some-long-string-of-numbers>
If it worked, the last number should be 1.
Example output: 6 0 0 0 1
If this process didn’t work and you didn’t miss anything, the wiki is the only hope.