Notes on installing Arch Linux

Published on

A few notes on installing Arch Linux


These notes are based on the following articles / wiki pages after I had to re-install ArchLinux on a new SSD. The task was more difficult than anticipated as it had been a while since my last installation. On top of that, I decided to use btrfs for the main system with a Luks encrypted container. On top of that, I wanted to have a working dual boot as Nvidia Optimus support is still not optimal on older generation.

So here are the requirements:

  • Dual boot with windows 10
  • Encrypted Linux partition
  • Swap file
  • Btrfs
  • No Password needed to boot windows


  • grub (/boot) partition will not be encrypted in order to boot windows without having to specify a password. I know this is not optimal, but is enough in my security threat model, which mainly resolves in protecting my documents in case my laptop is stolen.
  • This setup is temporary until I ditch windows completely from this laptop.

Based on

Step 1: boot the installation iso and preparation

On the PC:

  • I have a French layout keyboard so run loadkeys fr to set the mapping right.

  • Connect to a wireless network:


    station wlan0 connect SSID

  • We will connect with SSH to this PC from another one. It brings flexibilty in writing the installation commands. First, change the root password. passwd Start the ssh server daemon and get ip address:

systemctl start sshd	
ip addr

Now, from another computer: ssh root@[IP-ADDRESS]

Step 2: Prepare the disk


# fdisk -l

Device              Start        End    Sectors   Size Type
/dev/nvme0n1p1       4096     208895     204800   100M EFI System
/dev/nvme0n1p2     208896     720895     512000   250M Linux filesystem
/dev/nvme0n1p3     720896 1426968575 1426247680 680.1G Linux filesystem
/dev/nvme0n1p4 1426968576 1866235610  439267035 209.5G Microsoft basic data
/dev/nvme0n1p5 1866235904 1867286527    1050624   513M Windows recovery environm

  • sda1 - EFI
  • sda2 - grub ext4
  • sda3 - Luks
  • sda4 - ntfs

-> Use btrfs

Create luks container

# cryptsetup -y -v luksFormat /dev/nvme0n1p3
# cryptsetup open /dev/nvme0n1p3 cryptroot
# mkfs.btrfs -L arch /dev/mapper/cryptroot
# mount /dev/mapper/cryptroot /mnt

Check the mapping works as intended:

# umount /mnt
# cryptsetup close cryptroot
# cryptsetup open /dev/nvme0n1p3 cryptroot
# mount /dev/mapper/cryptroot /mnt

Create btrfs subvolume

# btrfs subvolume create /mnt/@
# btrfs subvolume create /mnt/@home
# btrfs subvolume create /mnt/@tmp
# btrfs subvolume create /mnt/@snapshots
# btrfs subvolume create /mnt/@swap

Check subvolumes

# btrfs subvolume list -p mnt

Remount with subvolume

# umount /mnt
# mount -o compress=zstd,subvol=@ /dev/mapper/cryptroot /mnt
# mkdir /mnt/{home,tmp,.snapshots,boot,swap}
# mount -o compress=zstd,subvol=@home /dev/mapper/cryptroot /mnt/home
# mount -o subvol=@tmp /dev/mapper/cryptroot /mnt/tmp
# mount -o compress=zstd,subvol=@snapshots /dev/mapper/cryptroot /mnt/.snapshots
# mount /dev/nvme0n1p2 /mnt/boot
# mkdir /mnt/boot/efi
# mount /dev/nvme0n1p1 /mnt/boot/efi

At this point, I have the following mounted:

root@archiso / # mount
/dev/mapper/cryptroot on /mnt type btrfs (rw,relatime,compress=zstd:3,ssd,space_cache,subvolid=257,subvol=/@)
/dev/mapper/cryptroot on /mnt/home type btrfs (rw,relatime,compress=zstd:3,ssd,space_cache,subvolid=258,subvol=/@home)
/dev/mapper/cryptroot on /mnt/tmp type btrfs (rw,relatime,compress=zstd:3,ssd,space_cache,subvolid=259,subvol=/@tmp)
/dev/mapper/cryptroot on /mnt/.snapshots type btrfs (rw,relatime,compress=zstd:3,ssd,space_cache,subvolid=263,subvol=/@snapshots)
/dev/mapper/cryptroot on /mnt/swap type btrfs (rw,relatime,compress=zstd:3,ssd,space_cache,subvolid=273,subvol=/@swap)

Create swapfile

# mount -o subvol=@swap /dev/mapper/cryptroot /mnt/swap
# chattr +C /mnt/swap
# touch /mnt/swap/swapfile
# chmod 600 /mnt/swap/swapfile

For 16GiB

# dd if=/dev/zero of=/mnt/swap/swapfile bs=1M count=16384 status=progress
# mkswap /mnt/swap/swapfile
# swapon /mnt/swap/swapfile

Create nested subvolume

# btrfs subvolume create /mnt/srv
# btrfs subvolume create /mnt/var/abs
# btrfs subvolume create /mnt/var/tmp
# btrfs subvolume create /mnt/var/lib/portables
# btrfs subvolume create /mnt/var/lib/machines
# btrfs subvolume create /mnt/var/cache/pacman/pkg

This is useful to avoid having these folders in the automatic snapshots of the root partition we will set up later.

You can check the existing subvolumes with:

root@archiso / # btrfs subvolume list -p mnt        
ID 257 gen 139 parent 5 top level 5 path @
ID 258 gen 22 parent 5 top level 5 path @home
ID 259 gen 22 parent 5 top level 5 path @tmp
ID 263 gen 15 parent 5 top level 5 path @snapshots
ID 264 gen 132 parent 257 top level 257 path @/srv
ID 265 gen 137 parent 257 top level 257 path @/var/tmp
ID 266 gen 25 parent 257 top level 257 path @/var/abs
ID 267 gen 137 parent 257 top level 257 path @/var/cache/pacman/pkg
ID 270 gen 135 parent 257 top level 257 path @/var/lib/portables
ID 271 gen 136 parent 257 top level 257 path @/var/lib/machines
ID 273 gen 141 parent 5 top level 5 path @swap

The paths starting with @/ are nested subvolumes.

Step 3: Installation

Optional - update mirrors (don’t know if it changes anything though)

# pacman -Sy reflector
# reflector --country France --country Germany --age 12 --protocol https --sort rate --save /etc/pacman.d/mirrorlist --verbose

Install arch base

# pacstrap /mnt base base-devel linux linux-firmware btrfs-progs zsh

Add intel-ucode if using an Intel CPU, amd-ucode if for AMD.


# genfstab -U -p /mnt >> /mnt/etc/fstab

Boot into new system

# systemd-nspawn -bD /mnt

Locale gen

# echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen
# echo "en_GB.UTF-8 UTF-8" >> /etc/locale.gen
# echo "fr_FR.UTF-8 UTF-8" >> /etc/locale.gen
# echo "co_FR.UTF-8 UTF-8" >> /etc/locale.gen
# locale-gen
# localectl set-locale LANG=en_US.UTF-8

- to check LC_COLLATE=C in /etc/locale.conf
# echo "LC_COLLATE=C" >> /etc/locale.conf

To check the locales were installed correctly:

$ localectl list-locales

I then configure them that way:


Time and Date

# timedatectl set-ntp 1
# timedatectl list-timezones
# timedatectl set-timezone Europe/Paris

Set hostname

# hostnamectl set-hostname xxx

Check hostfile

/etc/hosts	localhost
::1			localhost	myhostname.localdomain	myhostname

Keyboard Layout

If you set the keyboard layout, make the changes persistent in vconsole.conf(5):

# echo "KEYMAP=fr" >> /etc/vconsole.conf
# pacman -Sy vim iwd wpa_supplicant dialog terminus-font


Edit /etc/mkinitcpio.conf

BINARIES=(/usr/bin/btrfs) # see
HOOKS=(base udev autodetect keyboard keymap consolefont modconf block encrypt filesystems fsck) #no need for keymap if US keyboard
# mkinitcpio -P linux

Configuring the boot loader

-> Use grub here. See next section

Quit the container

# poweroff

Need arch-chroot for grub

# arch-chroot /mnt

Install grub

# pacman -S grub efibootmgr 
# pacman -S os-prober #for windows

In order to unlock the encrypted root partition at boot, the following kernel parameters need to be set by the boot loader: Use blkid to get the UUID. we want the UUID of the physical partition here

Edit /etc/default/grub as GRUB_CMDLINE_LINUX='cryptdevice=UUID=device-UUID:cryptroot root=/dev/mapper/cryptroot'

Then run:

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

## To check if we correctly booted in efi
# mount | grep efivars &> /dev/null || mount -t efivarfs efivarfs /sys/firmware/efi/efivars

# grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=GRUB --recheck

Step 4: System Installation

Install again reflector in our freshly install system:

# pacman -Sy reflector
# reflector --country France --country Germany --age 12 --protocol https --sort rate --save /etc/pacman.d/mirrorlist --verbose

Having the lts kernel can be handy in case of problems. I usually have dkms packages as well, so I install the headers alongside.

# pacman -S linux-lts linux-lts-headers linux-headers

NB: why did I add acpi_call-dkms here?

Intel related video drivers:

pacman -S intel-media-driver intel-compute-runtime libva-intel-driver intel-media-sdk xf86-video-intel

AMD related video drivers:

pacman -S xf86-video-ati xf86-video-amdgpu xf86-video-amdgpu mesa lib32-mesa

Nvidia drivers:

pacman -S nvidia nvidia-settings opencl-nvidia

Check the wiki for more information for both here.

Some system utils, network fonts & media plugins tools, xord server:

pacman -S cronie ntp git snap-pac nss_mdns dhcpcd dhclient neovim samba unrar logrotate rrdtool python2 bluez zip unzip p7zip vim alsa-utils syslog-ng mtools dosfstools lsb-release ntfs-3g exfat-utils bash-completion gst-plugins-{base,good,bad,ugly} gst-libav xorg-{server,xinit} xdg-user-dirs  ttf-{bitstream-vera,liberation,freefont,dejavu} freetype2 rsync libappimage ocl-icd lzop lrzip libnfs

Regulatory domain for Wi-Fi:

pacman -S crda

Uncomment this country setting in /etc/conf.d/wireless-regdom

To have the ability to print in a pdf:

pacman -S cups cups-pdf

To have printers drivers, add foomatic-{db,db-ppds,db-gutenprint-ppds,db-nonfree,db-nonfree-ppds} gutenprint ipp-usb

Enable system services

systemctl enable ntpd
#systemctl enable systemd-resolved.service ## not sure. apparently does not work with avahi. pkg systemd-resolvconf
systemctl enable syslog-ng@default
systemctl enable cronie
systemctl enable bluetooth
systemctl enable avahi-daemon
systemctl enable avahi-dnsconfd
systemctl enable org.cups.cupsd.socket ## according to the wiki, can start the daemon when smth is received on the socket
systemctl is-enabled org.cups.cupsd.socket ## should be True
systemctl is-enabled org.cups.cupsd.service ## should be False

Add new user

export MyUSER=XXX
useradd -m -g $MyUSER -G wheel,storage,uucp,audio,video,plugdev,users -c 'FULL NAME' -s /bin/zsh $MyUSER
--groupadd $MyUSER
--usermod -g $MyUSER $MyUSER

to check

groupadd plugdev
usermod -aG plugdev $MyUSER

Create a subvolume for our user cache folder:

btrfs subvolume create /home/$MyUSER/.cache

UI level service

Install plasma group and default apps, firefox and some utils.

pacman -S plasma appmenu-gtk-module kdegraphics-thumbnailers plasma-workspace-wallpapers breeze-gtk kwalletmanager drkonqi bluez-utils dolphin-plugins sddm
localectl set-x11-keymap fr
systemctl start sddm

If the above work, enable the service and reboot.

# systemctl enable sddm
# systemctl enable NetworkManager.service

Now we can reboot.

Step 5: System Installation for user

== Login as user


sudo pacman -S firefox ffmpegthumbs kimageformats keepass kate kate ktorrent thunderbird tilix hunspell-{fr,de,en_GB,en_US} okular libreoffice-fresh baobab


sudo pacman -S aria2 firejail ark android-tools android-udev gvfs-{afc,goa,google,gphoto2,mtp,nfs,smb} antiword docx2txt virtualbox htop i7z moreutils nvme-cli testdisk vdpauinfo powertop python-virtualenv python-pynvim ipython tree gparted

After installing virtualbox, don’t forget to add the user to the vboxusers group to be able to attach usb devices to the VM

sudo usermod -aG vboxusers $USER


sudo pacman -S pulseaudio pulseaudio-alsa paprefs pulseaudio-zeroconf pulseaudio-bluetooth

Video and images soft:

sudo pacman -S darktable displaycal colord-kde gnome-color-manager musescore gimp clementine kdenlive rawtherapee handbrake spectacle calibre shotwell vlc

NOTE: is mtpfs needed for android access??

Remove some pkg installed with the plasma group

sudo pacman -R discover plasma-vault

Install yay

git clone
cd yay
makepkg -si

Install oh my zsh

sh -c "$(curl -fsSL"

Install from aur

yay -S aic94xx-firmware airvpn-bin downgrade protonmail-bridge-bin rambox-bin tlpui-git upd72020x-fw vivaldi wd719x-firmware yay-bin ventoy-bin

Step 6: Various tweaks

Config to do

  • Reflector in /etc/xdg/reflector/reflector.conf Select countries, destination file. sudo systemctl enable reflector.timer to enable automatic update

  • iwd -> install networkmanager-iwd-overlay on AUR if lazy

  • swapiness: Decrease to 10 in /etc/sysctl.d/99-swappiness.conf

  • TLP: To avoid filesystem corruption on btrfs formatted partitions, in /etc/tlp.conf set: SATA_LINKPWR_ON_BAT=max_performance

  • PS1 used by root. add in /root/.bashrc. Looks like: [02:03 pm] root @machine {~} >

PS1="\[\033[38;5;6m\][\[$(tput sgr0)\]\[\033[38;5;14m\]\@\[$(tput sgr0)\]\[\033[38;5;6m\]]\[$(tput sgr0)\] \[$(tput sgr0)\]\[\033[38;5;11m\]\u\[$(tput sgr0)\] \[$(tput sgr0)\]\[$(tput bold)\]\[\033[38;5;10m\]@\[$(tput sgr0)\]\h\[$(tput sgr0)\] \[$(tput sgr0)\]\[\033[38;5;13m\]{\w}\[$(tput sgr0)\] > \[$(tput sgr0)\]"

Numlock in tty at boot

nvim /usr/local/bin/numlock

    for tty in /dev/tty{1..6}
        /usr/bin/setleds -D +num < "$tty";
chmod +x /usr/local/bin/numlock
nvim /etc/systemd/system/numlock.service


systemctl enable numlock.service 

Avoid ghosting of FN keys on MSI GS40

vim /etc/X11/xorg.conf.d/10-quirks.conf
Section "InputClass"
        Identifier "Spooky Ghosts"
        MatchProduct "Video Bus"
        Option "Ignore" "on"

Add the following in /etc/default/grub GRUB_CMDLINE_LINUX=“acpi_osi="!Windows 2015"” NB: it seems i915.enable_rc6=0 is ignored. To be investigated

GP AE Not found - ACPI ERROR

Kernel msg error - dmesg was flooded with:

Sep 17 13:09:59 xxx kernel: ACPI BIOS Error (bug): Could not resolve symbol [\_GPE._L69.D1F0], AE_NOT_FOUND (20190816/psargs-330)
Sep 17 13:09:59 xxx kernel: ACPI Error: Aborting method \_GPE._L69 due to previous error (AE_NOT_FOUND) (20190816/psparse-529)
Sep 17 13:09:59 xxx kernel: ACPI Error: AE_NOT_FOUND, while evaluating GPE method [_L69] (20190816/evgpe-511)

Check what is unusual (high nb)

$ grep . -r /sys/firmware/acpi/interrupts/

Add the kernel param to your bootloader: acpi_mask_gpe=0x[XX]

Pacman config and tweaks

In /etc/pacman.conf, untick the following options:

total download

and add the following repository (to your own risk):

SigLevel = Required
Server =$repo/$arch

From seblu repo or aur

yay -Sy virtualbox-ext-oracle spotify

Hdparm - put spinning disk to sleep

To enable this now (after 12*5 sec = 1min)

sudo hdparm -B 12 /dev/sda

Putting a drive to sleep directly after boot

vim /etc/systemd/system/hdparm.service
    Description=hdparm sleep

    ExecStart=/usr/bin/hdparm -q -S 12 /dev/sda

$ sudo systemctl enable hdparm.service

APM level reset after suspend

vim /etc/systemd/system/apm.service
    Description=Local system resume actions

    ExecStart=/usr/bin/hdparm -B 12 /dev/sda

$ sudo systemctl enable apm.service

Suspend on disk with swapfile on btrfs partition

Add resume hooks in /etc/mkinitcpio.conf

See the wiki c prgm to calculate file offset:

$ wget

to compile:

$ gcc -O2 -o btrfs_map_physical btrfs_map_physical.c

Get file offset:

$ sudo ./btrfs_map_physical /swap/swapfile | column -ts $'\t'

Get the top-right-hand corner value.

$ getconf PAGESIZE
$ dc -e 'number_in_top_right_hand_corner page_size /p'

Edit /etc/default/grub add resume=UUID=xxx OR resume=/dev/mapper/cryptroot (if dev mapper mounted there)

AND resume_offset=yyy -> being what was calculated above

Alternative command to suspend on disk:

# echo disk > /sys/power/state

Snapper - auto snapshot

Follow the instructions on the wiki and this chapter as well.

–> disable hourly snapshot of / partition by setting a var to no in /etc/snapper/configs/root

–> create config for home:

sudo snapper -c home create-config /home

For users to have access to snapshots. root must be owner but we can update the group

cd /
chmod a+rx .snapshots
chown :users .snapshots

Snapshot bootpartition if not on btrfs

See !! Check that rsync is installed

mkdir /.bootbackup
nvim /usr/share/libalpm/hooks/50_bootbackup.hook
    Operation = Upgrade
    Operation = Install
    Operation = Remove
    Type = Package
    Target = linux*

    Depends = rsync
    Description = Backing up /boot...
    When = PreTransaction
    Exec = /usr/bin/rsync -a --delete /boot /.bootbackup

TRIM ssd

disabled by default! add ``:allow-discards` in grub config file as option for mapper device. See the [wiki](

Then we can either add discard option in fstab for continuous tril or enable fstrim.timer` (weekly trim) for periodic trim


Check ext4 filesystem every 50 mounts or 2 weeks:

sudo tune2fs -c 50 -i 2w /dev/sdaX


Some nice grub theme

$ git clone
$ cd grub2-themes
$ sudo ./ -b -t # read man to select grub theme

Check intel audio power consumption

$ cat /sys/module/snd_hda_intel/parameters/power_save*
$ echo 1 | sudo tee /sys/module/snd_hda_intel/parameters/power_save
$ echo Y | sudo tee /sys/module/snd_hda_intel/parameters/power_save_controller
$ pkill pulseaudio

HW probe (to help the community)

$ aria2c
$ chmod +x ./hw-probe-1.5-149-x86_64.AppImage
$ sudo -E ./hw-probe-1.5-149-x86_64.AppImage -all -upload\n


The first thing to do is to run as root to calibrate the sensors

# sensors-detect

Touchpad sensitivity

$ yay -S xorg-xinput
$ xinput --set-prop 'ETPS/2 Elantech Touchpad' 'libinput Accel Speed' 0.017324

Other useful information

f-prot antivirus

For macOS vm

See Github’s project

$ yay -S dmg2img

Darktable crash with opencl

fxthomas commented on Aug 5 Thanks, by the way I can confirm that downgrading intel-graphics-compiler to 1.0.4361 (package link here) fixes the issue. Will open an issue on their GitHub when I get the time!

For some reason, clearing ~/.cache/darktable/cached_kernels*, downgrading, starting Darktable once with the previous version and then upgrading again seemed to fix the issue, now I have no issue with 1.0.4427.

Kwallet manager & gnome-keyring

Doc here

  • Install kwalletmanager kwallet-pam

  • Install gnome-keyring seahorse

Handle ssh keys and git credentials with

Install ksshaskpass and create an executable script ~/.config/plasma-workspace/env/


# Using the KDE Wallet to store ssh key passphrases
export SSH_ASKPASS='/usr/bin/ksshaskpass'
# Using the KDE Wallet to store Git credentials
export GIT_ASKPASS='/usr/bin/ksshaskpass'

and ~/.config/autostart-scripts/

ssh-add -q ~/.ssh/key1 ~/.ssh/key2 ~/.ssh/key3 < /dev/null

Note that a ssh-agent must be running.