Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save AhmedMostafa16/9d41d91129125b0c624e239376607091 to your computer and use it in GitHub Desktop.
Save AhmedMostafa16/9d41d91129125b0c624e239376607091 to your computer and use it in GitHub Desktop.

Arch install with encrypted BTRFS (LUKS2), GRUB e AwesomeWM

My notes with the steps to install Arch Linux with encrypted BTRFS (LUKS2) and GRUB.

If you stumbled upon this document looking for a guide to install Arch Linux, I recommend checking the official installation guide on the Arch Linux Wiki: https://wiki.archlinux.org/title/Installation_guide. This is not a guide, just some notes that I'm taking while trying this setup and getting fragments of information from the internet.

If you want to try this steps... Well, it worked for me, but I'm not responsible for any damage that you may cause to your system.

I have no idea what I'm doing

Table of contents

Download and boot

Download and write the official Arch Linux ISO to a USB stick.

Usually I have a usb stick with ventoy and multiple ISOs, but if I want to write only the Arch Linux ISO to a USB stick, I use usbimager.

It may be necessary to disable secure boot in the BIOS.

Links

Adjusts during installation

I recommend using tmux so you can see long outputs and split the terminal if needed.

Set the keyboard layout

loadkeys

br-abnt2: Brazilian ABNT2 us: US us-acentos: US international

# PT BR ABNT2
loadkeys br-abnt2

localectl

br-abnt2: Brazilian ABNT2 us: US us-acentos: US international

# List available keymaps
localectl list-keymaps

# Set BR ABNT2
localectl set-keymap us-acentos

Fix font size

The font may be to small during the installation.

Changing installation font (reddit + arch wiki):

# List available fonts
ls /usr/share/kbd/consolefonts/

# Change to another font (my recomendation: ter-132n)
setfont ter-132n

Verify the boot mode

If you are using UEFI, the directory /sys/firmware/efi/efivars should exist.

# If the directory does not exist, the system is booted in BIOS mode
ls /sys/firmware/efi/efivars

Connecting to the internet with Wi-Fi

If you are using Wi-Fi, execute iwctl and the following commands:

device list # list the devices
station <wlan> scan # scan for networks
station <wlan> get-networks # list the networks
station <wlan> connect <SSID> # connect to the network

ps: you can test the connection with ping archlinux.org.

Preparing the disks

I will delete all partitions on the disk and create new ones. If you have data on the disk, backup it before continuing or adjust the steps to keep the data.

Partition the disk

Use fdisk to partition the disk.

# Start the fdisk interactive mode (for the example, it will be "/dev/sda" disk)
fdisk /dev/sda

# List all partitions
p

# Create a new GPT partition layout (this will erase all data on the disk)
g

# Create a new partition (partition for EFI)
# 500M should be enough, however, I prefer to use 1G to be sure
n
> Partition number (1-128, default 1): # use default
> First sector (2048-1048575966, default 2048): # use default
> Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-1048575966, default 1048575966): +1G

# Set the type EFI
t
> Partition type or alias (type L to list all): 1 # EFI

# Create a second partition (partition for /boot (grub))
# 500M should be enough here too
n
> Partition number (2-128, default 2): # use default
> First sector (1026048-1048575966, default 1026048): # use default
> Last sector, +/-sectors or +/-size{K,M,G,T,P} (1026048-1048575966, default 1048575966): +1G

# (Optional) Create a swap partition
# 8G should be fine for most cases
n
> Partition number (3-128, default 3): # use default
> First sector (2050048-1048575966, default 2050048): # use default
> Last sector, +/-sectors or +/-size{K,M,G,T,P} (2050048-1048575966, default 1048575966): +8G

# Set the type SWAP
t
> Partition type or alias (type L to list all): swap # Linux swap

# Change partition name to cryptoswap
# Enter extra functionality mode
x

# Change the partition name
n
Partition number (1-3, default 3): 3
New name: cryptswap

# Return to the main menu
r

# Create a fourth partition (partition for /)
n
> Partition number (4-128, default 4): # use default
> First sector (10242048-1048575966, default 10242048): # use default
> Last sector, +/-sectors or +/-size{K,M,G,T,P} (10242048-1048575966, default 1048575966): # use default

# Change the partition name
n
Partition number (1-4, default 4): 4
New name: cryptsystem

# Return to the main menu
r

# Check partitions, should have two 1G partitions, one 8G partition and one
# partition with the remaining space. The first partition should be EFI, the
# second and fourth should be Linux filesystem and the third should be SWAP
p

# Write the partition table and exit fdisk
w

# List disks (should be same output as we got before in the fdisk prompt (when
# used the command "p" before "w"))
fdisk -l

Encrypt the partition

# Encrypt the root partition
cryptsetup luksFormat --type=luks2 /dev/sda4

# Open the encrypted partition
cryptsetup open --type=luks2 /dev/sda4 system

# Open swap as crypt device
cryptsetup open --type plain --key-file /dev/urandom /dev/sda3 swap

Configure swap

# Format the swap partition
mkswap -L swap /dev/mapper/swap

# Enable the swap partition
swapon -L swap

Create the filesystems

# Create the EFI filesystem
mkfs.fat -F32 /dev/sda1

# Create the /boot filesystem
mkfs.ext4 /dev/sda2

# Create the root filesystem
# mkfs.btrfs /dev/mapper/system
mkfs.btrfs -L system /dev/mapper/system

Configure the BTRFS subvolumes

# Mount the root filesystem
mount -t btrfs LABEL=system /mnt

# Create the root subvolume
btrfs subvolume create /mnt/@root

# Create the home subvolume
btrfs subvolume create /mnt/@home

# Create the var subvolume
btrfs subvolume create /mnt/@var

# Create the tmp subvolume
btrfs subvolume create /mnt/@tmp

# Create the snapshots subvolume
btrfs subvolume create /mnt/@snapshots

# Unmount the root filesystem
umount -R /mnt

Mounting the subvolumes and partitions

# Mount the root subvolume
mount -t btrfs -o defaults,x-mount.mkdir,compress=zstd,ssd,noatime,subvol=@root LABEL=system /mnt

# Mount the snapshots subvolume
mount -t btrfs -o defaults,x-mount.mkdir,compress=zstd,ssd,noatime,subvol=@snapshots LABEL=system /mnt/.snapshots

# Mount the var subvolume
mount -t btrfs -o defaults,x-mount.mkdir,compress=zstd,ssd,noatime,subvol=@var LABEL=system /mnt/var

# Mount the tmp subvolume
mount -t btrfs -o defaults,x-mount.mkdir,compress=zstd,ssd,noatime,subvol=@tmp LABEL=system /mnt/tmp

# Mount the home subvolume
mount -t btrfs -o defaults,x-mount.mkdir,compress=zstd,ssd,noatime,subvol=@home LABEL=system /mnt/home

# Mount the boot partition
mkdir /mnt/boot
mount /dev/sda2 /mnt/boot

Setting up fstab file

Create the fstab with the current mount points:

# Creating etc directory
mkdir /mnt/etc

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

Installing Arch Linux

Base packages

Install base packages for Arch Linux:

# Install only the base packages
pacstrap /mnt base

Configure swap encryption

Configure crypttab to encrypt the swap partition:

# Get PARTUUID of the swap partition (remember that /dev/sda3 is the swap partition)
blkid /dev/sda3

# Open the crypttab file
nvim /mnt/etc/crypttab

# Add the swap partition to the crypttab file
swap PARTUUID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX /dev/urandom swap,offset=2048,cipher=aes-xts-plain64,size=256

Verify if swap is correct in fstab:

# /dev/mapper/swap LABEL=swap
/dev/mapper/swap none swap defaults 0 0

Observation: although I'm using UUID for most things, the swap partition I was only able to make it work with the /dev/mapper/swap path.

Install additional packages

Configure installation through chroot environment:

# Attach to work in progress installation in chroot environment
arch-chroot /mnt

# linux linux-headers: install kernel latest and lts
# linux-firmware: firmware for the kernel
# nvim: a text editor (nvim, vim, neovim...)
# base-devel is a group of development packages that is often needed
# openssh allows you to use ssh to manage the installation remotely
# networkmanager: network support and wifi support
# btrfs, lvm, ntfs-3g: support to filesystems
# zsh: my preferred shell
pacman -S linux linux-headers \
          linux-lts linux-lts-headers \
          mkinitcpio \
          linux-firmware \
          neovim \
          base-devel openssh \
          networkmanager \
          btrfs-progs lvm2 ntfs-3g \
          zsh zsh-completions

# Enabling ssh service (if you want to manage the installation remotely)
systemctl enable sshd

# Enabling network manager
systemctl enable NetworkManager

Configuring mkinitcpio

Edit the mkinitcpio configuration (/etc/mkinitcpio.conf) file to add encrypt and btrfs to the HOOKS array (before filesystems):

HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block encrypt btrfs filesystems fsck)

Generate the initramfs:

mkinitcpio -P

Configuring locale

Edit the /etc/locale.gen and uncomment the desired locales.

...
#en_SG.UTF-8 UTF-8
#en_SG ISO-8859-1
en_US.UTF-8 UTF-8
#en_US ISO-8859-1
#en_ZA.UTF-8 UTF-8
...
#pl_PL ISO-8859-2
#ps_AF UTF-8
pt_BR.UTF-8 UTF-8
#pt_BR ISO-8859-1
#pt_PT.UTF-8 UTF-8
...

Generate the locales:

locale-gen

Setting users and passwords

Set a secure password for root user

# execute as root user...
passwd

Create an user account

useradd -m -U -G wheel,users --shell /usr/bin/zsh <user_name>
passwd <user_name>

Install sudo if not installed

pacman -S sudo

Associating the wheel group with sudo

Open the sudoers file using visudo, you can force nvim putting EDITOR=nvim in front of the visudo command:

# Open sudoers file in nvim
EDITOR=nvim visudo

Uncomment the line %wheel ALL=(ALL) ALL and save the file:

## Uncomment to allow member of group wheel to execute any command
%wheel ALL=(ALL) ALL

Installing GRUB

Install GRUB, tools and UEFI support:

pacman -S grub grub-btrfs efibootmgr dosfstools os-prober mtools

Creating EFI directory for GRUB and mounting the EFI partition on the new directory:

# Creating EFI directory
mkdir /boot/EFI

# Mounting first partition on /boot/EFI (remember to check the partition, it
# should be the EFI partition, in this case, /dev/sda1)
mount /dev/sda1 /boot/EFI

Installing GRUB on the master boot record:

grub-install --target=x86_64-efi --bootloader-id=grub_uefi --recheck

Setting GRUB locale/language (1:24:02):

# Check if locale folder exists in /boot/grub
ls -l /boot/grub

# If it doesn't exist, create it
mkdir /boot/grub/locale

# Copy grub locale file from /usr/share/locale to /boot/grub/locale
cp /usr/share/locale/en\@quot/LC_MESSAGES/grub.mo /boot/grub/locale/en.mo

Edit the /etc/default/grub file to add/set the encryption settings:

# Opening default grub config file with nvim
nvim /etc/default/grub

Uncomment the line GRUB_ENABLE_CRYPTODISK=y:

# Uncomment to enable booting from LUKS encrypted disks
GRUB_ENABLE_CRYPTODISK=y

Search other operational systems

If you want that grub search for other operational systems, you can also uncomment the line GRUB_DISABLE_OS_PROBER=false:

GRUB_DISABLE_OS_PROBER=false

Remember last selected entry

If you want that grub remember the last selected entry, you can also uncomment the line GRUB_SAVEDEFAULT=true and change the line GRUB_DEFAULT=0 to GRUB_DEFAULT=saved:

...
GRUB_DEFAULT=saved
...
GRUB_SAVEDEFAULT=true
...

Edit the line with GRUB_CMDLINE_LINUX_DEFAULT="loglevel=3 quiet" adding the parameters cryptdevice=UUID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX:system:allow-discards before the "loglevel" (UUID is the one from the encrypted partition):

# get the UUID of the encrypted partition
blkid /dev/sda4

# Example:
GRUB_CMDLINE_LINUX_DEFAULT="cryptdevice=UUID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX:system:allow-discards loglevel=3 quiet"

Generate the grub configuration file:

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

Exiting chroot and rebooting:

# Exiting chroot
exit

# Unmounting all partitions
umount -a

# Reboot the system
reboot

Post-install Tweaks

Boot the system and log as the user that was created.

Most commands require root privileges, so you can use sudo before each command or use su to become root.

su

Timezone, Locale and Time Sync

Setting up timezone

# Check for available timezones
timedatectl list-timezones

# Set timezone to your location (America/Sao_Paulo for me)
timedatectl set-timezone America/Sao_Paulo

Enabling services for time sync

Enabling systemd-timesyncd service so that the system syncs the time at start

# Sync time at start
systemctl enable systemd-timesyncd

Hostname and Hosts File

Set machine hostname

# File /etc/hostname probably doesn't exists yet
cat /etc/hostname

# Set hostname as a name of your choice
hostnamectl set-hostname <hostname>

# Now the file /etc/hostname was generated
cat /etc/hostname

Editting the hosts file

Open the file /etc/hosts:

nvim /etc/hosts

Add the following lines to the file:

127.0.0.1 localhost
127.0.1.1 <hostname>

Observation: Use the name chosen as hostname instead of <hostname>.

Installing Micro Code For CPU

Install micro code for AMD or Intel CPU so that the system can take advantage of the latest CPU features and security updates.

For AMD CPU:

pacman -S amd-ucode

For Intel CPU:

pacman -S intel-ucode

Installing Xorg and GPU Drivers

Install xorg and gpu drivers (no wayland yet... I like awesome wm too much and I am too lazy to update my config and scripts to work with wayland):

# If you have an intel or amd GPU, install the mesa package
pacman -S mesa

# If you have a nvidia GPU, install the nvidia or nvidia-lts packages (or both)
pacman -S nvidia nvidia-lts

# Installing xorg
pacman -S xorg-server

Pacman configuration

Enable multilib

Enabling multilib (required for some packages, like steam for example) (arch wiki reference):

Uncomment section [multilib] in /etc/pacman.conf:

[multilib]
Include = /etc/pacman.d/mirrolist

Optimize downloads

# Enable this option to enable parallel downloads
ParallelDownloads = 5

Customize output

# Enable this option to enable color output
Color

# Add this secret option to make pacman output more visually appealing
ILoveCandy

Package manager for AUR

Yay is a wrapper for pacman that allows you to install packages from the AUR. The syntax is similar to pacman, so it's easy to use.

Obs.: Use those commands as normal user, not as root.

# Essential dependencies
pacman -S base-devel git

# Clone yay repository
git clone https://aur.archlinux.org/yay.git

# Enter the directory
cd yay

# Build and install the package
# Observation: in the guide, he uses only `makepkg -s`, but for me it only works with `makepkg -si`
makepkg -si

Numlock at early boot (mkinitcpio)

Activating numlock at early boot (if the password has numbers, it can be useful) (arch wiki reference):

# Install AUR package mkinitcpio-numlock
yay -S mkinitcpio-numlock

# Edit the file `/etc/mkinitcpio.conf`
nvim /etc/mkinitcpio.conf

In the line HOOKS=(... move keyboard to before modconf, and add keymap, consolefont and numlock after keyboard. Example:

HOOKS=(base udev autodetect keyboard keymap consolefont numlock modconf block encrypt btrfs filesystems fsck)

Locale.conf With Fallback

My locale.conf file with fallback (arch wiki reference):

LANG="en_US.UTF-8"
LANGUAGE="en_US:en:C:pt_BR"
LC_ADDRESS="pt_BR.UTF-8"
LC_COLLATE="pt_BR.UTF-8"
LC_CTYPE="pt_BR.UTF-8"
LC_IDENTIFICATION="pt_BR.UTF-8"
LC_MEASUREMENT="pt_BR.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_MONETARY="pt_BR.UTF-8"
LC_NAME="pt_BR.UTF-8"
LC_NUMERIC="pt_BR.UTF-8"
LC_PAPER="pt_BR.UTF-8"
LC_TELEPHONE="pt_BR.UTF-8"
LC_TIME="pt_BR.UTF-8"

Configure XDG directories

Edit the /etc/security/pam_env.conf to set the XDG directories:

Add the following lines to the file:

XDG_CONFIG_HOME DEFAULT=@{HOME}/.config
XDG_DATA_HOME   DEFAULT=@{HOME}/.local/share
XDG_STATE_HOME  DEFAULT=@{HOME}/.local/state
XDG_CACHE_HOME  DEFAULT=@{HOME}/.cache

ps: Some directories may not exist yet, so use mkdir just in case.

mkdir -p ~/.config
mkdir -p ~/.local/share
mkdir -p ~/.local/state
mkdir -p ~/.cache

Configuring ZDOTDIR

Edit the /etc/zsh/zshenv to set the ZDOTDIR:

Add the following lines to the file:

ZDOTDIR=$HOME/.config/zsh

Installing AwesomeWM

AwesomeWM installation

Install awesome wm package

pacman -S awesome

Copy the default configuration to the user directory:

mkdir ~/.config/awesome
cp /etc/xdg/awesome/rc.lua ~/.config/awesome/rc.lua

Edit the rc.lua file to set the default terminal emulator to alacritty:

nvim ~/.config/awesome/rc.lua

Find the line terminal = "xterm" and change it to terminal = "alacritty".

Window manager and login manager

Install a login manager (I use lightdm) and a terminal emulator (I use alacritty):

pacman -S lightdm lightdm-gtk-greeter lightdm-gtk-greeter-settings

Enable the lightdm service:

systemctl enable lightdm

Basic applications for a desktop environment

Firefox: web browser PCManFM: file manager Alacritty: terminal emulator PipeWire: audio server

pacman -S firefox pcmanfm-gtk3 alacritty pipewire pipewire-pulse pipewire-jack

Enable user services for pipewire:

systemctl --user enable pipewire
systemctl --user enable pipewire-pulse

Persist keyboard layout

sudo setxkbmap -layout br -variant abnt2

Install flatpak

pacman -S flatpak xdg-desktop-portal xdg-desktop-portal-gtk

BTRFS snapshots

Create first snapshot (clean install)

btrfs subvolume snapshot / /.snapshots/@clean-install

Pacman hook for snapshots

Create a pacman hook to create a snapshot before and after a system upgrade (arch wiki reference):

# Create the directory for the pacman hooks
mkdir /etc/pacman.d/hooks

# Create the file for the pacman hook
nvim /etc/pacman.d/hooks/90-btrfs-snapshot.hook

Add the following lines to the file:

[Trigger]
Type = Package
Operation = Install
Operation = Upgrade
Operation = Remove
Target = linux
Target = linux-lts
Target = nvidia
Target = nvidia-lts
Target = intel-ucode
Target = grub

[Action]
Description = Creating BTRFS snapshot before system upgrade
When = PreTransaction
Exec = /usr/bin/bash -c '/usr/bin/btrfs subvolume snapshot / /.snapshots/@root-snapshot-$(date +%Y-%m-%d-%H-%M)'
AbortOnFail

Pacman hook for grub update

Create another pacman hook to update the grub configuration file after a system upgrade:

# Create the file for the pacman hook
nvim /etc/pacman.d/hooks/91-grub-mkconfig.hook

Add the following lines to the file:

[Trigger]
Type = Package
Operation = Install
Operation = Upgrade
Operation = Remove
Target = linux
Target = linux-lts
Target = nvidia
Target = nvidia-lts
Target = intel-ucode
Target = grub

[Action]
Description = Update grub cfg so it can boot from new snapshots
When = PostTransaction
Exec = /usr/bin/bash -c '/usr/bin/grub-mkconfig -o /boot/grub/grub.cfg'

Restoring a snapshot

Very important! I never actually needed this, I just tested once to see if it worked, but I never had to use it in practice and I'm not sure if this is the correct way to do it...

  1. Boot from a snapshot using grub-btrfs.

  2. Do the following steps:

# list btrfs subvolumes
btrfs subvolume list /

# boot the desired snapshot to restore
mount -t btrfs -o subvolid=<subvol_id> /dev/mapper/system /mnt

# to check mounted btfrs subvolumes you can use findmnt
findmnt -t btrfs

# edit the fstab file to change the id of the root subvolume
nvim /mnt/etc/fstab
# UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx / btrfs rs,noatime,compress=zstd,ssd,space_cache,subvolid=256,subvol=@root 0 0
# =>
# UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx / btrfs rs,noatime,compress=zstd,ssd,space_cache,subvolid=<NEW_ID>,subvol=@root 0 0

# Unmount the root filesystem
umount -R /mnt

# mount subvolid 5 in some directory
mount -t btrfs -o subvolid=5 /dev/mapper/system /mnt

# go to the mounted directory
cd /mnt

# rename @root to @root.bak
mv @root @root.bak

# rename @snapshots/@root-snapshot-2021-09-01-00-00 to @root
mv @snapshots/@root-snapshot-2021-09-01-00-00 @root

# umount the filesystem
umount /mnt

reboot

Customizations

This is a simple install, it is a good idea to give a look into archwiki "General recommendations" and archwiki "Improving performance".

Besides that, now it is just a matter of customizing the system to your needs. :)

References

root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
max_line_length = 80
trim_trailing_whitespace = true
[*.html]
max_line_length = 120
[*.md]
indent_size = 2
insert_final_newline = true
max_line_length = 80
trim_trailing_whitespace = false
{
"$schema": "http://json.schemastore.org/prettierrc",
"proseWrap": "always"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment