My First Arch Linux Installation
Tags: archlinux, linux, beginners
Published: 2024-06-12 18:07:49

- I post it originally on [my personal blog](https://www.dantas15.com/blog/first-arch-install/) and I recommend you read it there!

During a specific vacation from college, I figured I should try installing Arch Linux just because I was curious (and I wanted to say I use Arch btw).

## My expectations

- Learn! Since it's the first time I'm installing Arch Linux in a physical machine, I want to learn as much as I can, and write them down as much as possible
- Minimal installation
- Disk encryption
- Snapshots

### What you should expect (disclaimer)

This is not a tutorial (although I wrote it as a tutorial for me). This is just a report from my first time installing Arch in a physical computer.

You can use it as a kickstart for your own Arch install, or just see how I take notes.

Make sure to double check the information since they might not be completely up-to-date or outlined in a more simplistic way compared to the reality (always check the [Arch Wiki](https://wiki.archlinux.org/)).

Anyways, if you have any doubt or suggestions, make sure you [reach me](https://www.dantas15.com/contact).

## First things first

- [Download](https://archlinux.org/download/) the ISO
- Prepare an installation medium (I use [Ventoy](https://www.ventoy.net/en/index.html))

## Installation


You can change the keyboard layout as well. Layouts can be listed with:

```bash
localectl list-keymaps
```

Since my laptop is ABNT-2 (Brazil's default), I can change it with:

```bash
loadkeys br-abnt2
``` 

Also, this is completely optional, but I like to change the font:

```bash
setfont Lat2-Terminus16
```

### Network and Internet connection

<Callout>
  In the installation image, [systemd-networkd](https://wiki.archlinux.org/title/Systemd-networkd "Systemd-networkd"),
  [systemd-resolved](https://wiki.archlinux.org/title/Systemd-resolved "Systemd-resolved"), [iwd](https://wiki.archlinux.org/title/Iwd "Iwd") and
  [ModemManager](https://wiki.archlinux.org/title/ModemManager "ModemManager") are preconfigured and enabled by default.
</Callout>

Since I was using wired connection, I didn't need to setup anything, but, if it's not your case (something's not right or you're using wireless connection, check [this](https://wiki.archlinux.org/title/Iwd#iwctl)).

- To test if you're connected to the internet, ping any website:

```bash
  ping archlinux.org
```

### System clock

Now it's time to check if everything is right running `timedatectl`.

- You can list the timezones with:

```shell
timedatectl list-timezones
```

- Then you can select your timezone, for example `America/Sao_Paulo`:

```shell
timedatectl set-timezone America/Sao_Paulo
```

### Disk partitioning


  - I strongly recommend you to disconnect other disks except for the one you'll be Installing Arch so you don't erase anything you didn't want to
  - If there's any error, first check the [docs](https://wiki.archlinux.org/title/Installation_guide#Partition_the_disks) to see if any of the notes can help

- Identify the disk you'll be partitioning

```bash
fdisk -l
```

- I'll be using `/dev/sda/` but you should change it according to your case

- Use the `fdisk` specifying the disk

```bash
fdisk /dev/sda
```

- If the device does not contain a recognized partition table, `fdisk` [will automatically create a DOS (MBR) disklabel](https://unix.stackexchange.com/questions/685924/fdisk-output-new-dos-disklabel). Although it changes automatically to `gpt` once you create a GPT partition, you can already start the disk with GPT using the `-t` flag:

  ```bash
  fdisk -t gpt /dev/sda
  ```


Assuming you're in fdisk:

- To create a [partition table](https://wiki.archlinux.org/title/Partitioning#Partition_table), type `g`
- Now in order to create the boot partition, now type `n`
  - Select the first sector (kind of the starting point of the partition), the default (for the first partition) is 2048
  - Select the last sector. There are a few tips on how to select them:
    - Use the `+` symbol by the partition size
    - The size can be specified in kibibytes (K), mebibytes (M), gibibytes (G), tebibytes (T), or pebibytes (P)
    - Since it's the boot partition I'll set 1GiB with `+1G`
  - The default type for newly created partitions is `Linux Filesystem`
  - Since it's the boot partition, the type has to be changed. For that, type `t`
    - Then specify the type (type `L` to list all available types)
    - The `EFI System` type is `1`
- Repeat this process as needed in order to create the desired partitions
  - Personally, I just create another partition with the rest of the available space (all defaults)
- When you finish creating the partitions, type `w` to write changes to the disk

Create a FAT 32 system on the EFI partition (in my casse it's `/dev/sda1`):

```bash
mkfs.fat -F 32 /dev/sda1
```

## System encryption

Initialize encryption on the Linux Filesystem partition. It'll prompt a password to encrypt your system:

```bash
cryptsetup -y -v luksFormat /dev/sda2
```

Map `/dev/sda2` to `/dev/mapper/cryptroot`:

```bash
cryptsetup open /dev/sda2 root
```

## BTRFS parititioning and Swapfile

Create BTRFS on the encrypted Linux Filesystem partition:

```bash
mkfs.btrfs /dev/mapper/cryptroot
```

Now mount it:

```bash
mount /dev/mapper/cryptroot /mnt
```

`cd` to `/mnt` and create the subvolumes [as recommended](https://wiki.archlinux.org/title/snapper#Suggested_filesystem_layout) for use with `snapper` (a program I found on Cody Hou's Arch installation, [reference](#reference) below):

```bash
cd /mnt
btrfs subvolume create @
btrfs subvolume create @home
btrfs subvolume create @snapshots
btrfs subvolume create @var_log
btrfs subvolume create @swap
```

Unmount `root` and remount the subvolumes and the boot partition. [noatime](https://opensource.com/article/20/6/linux-noatime) is used for better performance [zstd](https://github.com/facebook/zstd) as file compression:

```bash
cd
umount /mnt
mount -o noatime,compress=zstd,space_cache=v2,subvol=@ /dev/mapper/cryptroot /mnt
mkdir -p /mnt/{boot,home,.snapshots,var/log,swap}
mount -o noatime,compress=zstd,space_cache=v2,subvol=@home /dev/mapper/cryptroot /mnt/home
mount -o noatime,compress=zstd,space_cache=v2,subvol=@snapshots /dev/mapper/cryptroot /mnt/.snapshots
mount -o noatime,compress=zstd,space_cache=v2,subvol=@var_log /dev/mapper/cryptroot /mnt/var/log
mount -o noatime,subvol=@swap /dev/mapper/cryptroot /mnt/swap
mount /dev/sda1 /mnt/boot
```

- Make sure the swap subvolume is not being snapshoted.

Create a [swap file](https://wiki.archlinux.org/title/Btrfs#Swap_file). Change the `count` parameter in order to specify the size of the swap file:

```bash
cd /mnt/swap
chattr +C /mnt/swap
dd if=/dev/zero of=./swapfile bs=1M count=8192 status=progress
chmod 0600 ./swapfile
```

Now you can install the [essential packages](https://wiki.archlinux.org/title/Installation_guide#Install_essential_packages) in your system. (replace `intel-ucode` with `intel-ucode`if you're using an Intel processor):

```bash
pacstap -K /mnt base base-devel linux linux-firmware amd-ucode vim git networkmanager btrfs-progs dosfstools e2fsprogs exfat-utils ntfs-3g smartmontools dialog man-db man-pages texinfo pacman-contrib
```

## Configuring the system

### Fstab

Generate [fstab](https://wiki.archlinux.org/title/Fstab):

```bash
genfstab -U /mnt >> /mnt/etc/fstab
```

### Chroot

Change root into the system:

```bash
arch-chroot /mnt
```

### Time

Set the time zone accordingly (you can look in /usr/share/zoneinfo for your region and city):

```bash
ln -sf /usr/share/zoneinfo/America/Sao_Paulo /etc/localtime
```

Run `hwclock` to generate `/etc/adjtime`:

```bash
hwclock --systohc
```

### Localization

Edit `/etc/locale.gen` and uncomment the needed UTF-8 locales (In my case, I'll uncomment `en_US.UTF-8 UTF-8` and `pt_BR.UTF-8 UTF-8`):

```bash
vim /etc/locale.gen
```

After you uncomment the locales, you have to generate the locales:

```bash
locale-gen
```

Now you can create `/etc/locale.conf` file:

```bash
vim /etc/locale.conf
```

And set the LANG variable accordingly:

```bash
LANG=pt_BR.UTF-8
```

Also, if you're using a keyboard layout other than US, you might want to persist the current keyboard layout. In `/etc/vconsole.conf`:

```bash
KEYMAP=br-abnt2
```

### Network configuration

Set the hostname (name of your machine) by creating the `/etc/hostname` and adding the name of your hostname inside it.

Now, in order to prevent software unsafely resolving localhost over the network because they migh still read `/etc/hosts`, add the following entries to `/etc/hosts`:

```bash
127.0.0.1        localhost
::1              localhost
127.0.1.1        yourhostname
```

### User configuration

Create a root password:

```bash
passwd
```

Create your user with administrative privileges (the `-s` can be omitted as bash is the default shell). In my case, my username will be `gus`:

```bash
useradd -m -G wheel,rfkill -s /bin/bash gus
```

Specify the password for the created user:

```bash
passwd gus
```

In order to enable the recently created user to have administrative privileges (e.g. be able to use `sudo`), you'll need to uncomment the `wheel` line on:

```bash
EDITOR=vim visudo
```

If you want, you can specify the full user name with:

```bash
chfn -f "Gustavo Dantas" gus
```

### Initramfs

In `/etc/mkinitcpio.conf`, add `btrfs` to `MODULES`

Still in `/etc/mkinitcpio.conf`, make sure the `HOOKS` looks like the following

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

- The order of the hooks matter, so make sure `block` and `encrypt` are before `filesystems`


Regenerate `initramfs`:

```bash
mkinitcpio -P
```

### Boot loader

You can use [grub](https://wiki.archlinux.org/title/GRUB) or [systemd](https://wiki.archlinux.org/title/systemd). I'll use grub because it enables more customization and there are some packages that allows restoring snapshots from the grub interface as well.

```bash
pacman -S grub efibootmgr
```

Generate the bootloader:

```bash
grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB
```

Now you need to obtain the UUID of the partition the system was installed:

```bash
blkid
```

-  Use the UUID of the partition itself (in my case it's `/dev/sda2`, or if you're using NVME it should be something like `/dev/nvme0n1p2)`


Edit `/etc/default/grub` and at the line beginning with `GRUB_CMDLINE_LINUX_DEFAULT`, insert at the end with a space after quiet. Replace the content of `[UUID]` with the correspondent UUID of your system partition:

```bash
root=/dev/mapper/cryptroot cryptdevice=UUID=[UUID]:root 
```

Regenerate `grub.cfg`:

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

Now it's time to add or configure additional software, like:

- Enabling networking on reboot:

```bash
systemctl enable NetworkManager.service
```

- Pacman cache clearner:

```bash
systemctl enable paccache.timer
```

- And if you're using SSD, enable TRIM:

```bash
systemctl enable fstrim.timer
```

It's time to exit chroot, reboot the system and remove the installation medium.

You should be prompted to enter the password of the encrypted partition right before loggin in.


- If what described above didn't happened, something not right happened along the process, like the UUID isn't correct.
  - In this case, you should use your installation medium again, remount all the partitions and use [arch-chroot](#chroot) to fix this 


## Snapshots

Install `snapper`:

```bash
sudo pacman -S snapper
```

When the snapshot configuration is created with `snapper`, it will also create a subvolume and a folder called `/.snapshots`, even thouth the `snapshots` subvolume was alreay created and mounted on `/.snapshots`

To fix this:

1. Unmount `snapshots` subvolume

```bash
sudo umount /.snapshots
```

2. Delete the `/.snapshots` folder

```bash
sudo rm -r /.snapshots
```

3. Create `snapper` config
    ```bash
    sudo snapper -c root create-config /
    ```

    - Check that snapper created the subvolume

    ```bash
    sudo btrfs subvolume list /
    ```
4. Delete the newly created subvolume and folder

```bash
sudo btrfs subvolume delete /.snapshots
```

5. Create the `/.snapshots` folder again

```bash
sudo mkdir /.snapshots
```

6. Remount it to snapshots subvolume

```bash
sudo mount -a
```

Now give the right read, write and execute permissions to the snapshots:

```bash
sudo chmod 750 /.snapshots
```

Add your user to `ALLOW_USERS="yourusername"` in the snapper config at `/etc/snapper/configs/root`. You can also change the frequency and the history listed on the snapper [wiki page](https://wiki.archlinux.org/title/snapper#Set_snapshot_limits):

```bash
sudo vim /etc/snapper/configs/root
```

Enable the snapper services:

```bash
sudo systemctl enable --now snapper-timeline.timer
sudo systemctl enable --now snapper-cleanup.timer
```

### AUR helper

An [AUR helper](https://wiki.archlinux.org/title/AUR_helpers) automates the usage of the Arch User Repository (which is one of the great pros about using Arch really).

Even when I used Arch on WSL, I really liked [yay](https://github.com/Jguer/yay), because it's really fun to type :)

But you can also choose another one (like [paru](https://aur.archlinux.org/packages/paru) which is written in Rust), or if you're really going in Arch Linux way, get familiar with the [manual build process](https://wiki.archlinux.org/title/Arch_User_Repository#Installing_and_upgrading_packages)

Anyway, I'm installing `yay`. From the [docs](https://github.com/Jguer/yay?tab=readme-ov-file#installation):

```bash
pacman -S --needed git base-devel && git clone https://aur.archlinux.org/yay-bin.git && cd yay-bin && makepkg -si
```

In order to take a snapshot after every single install with pacman so you can revert if an upgrade breaks something, we can use `snap-pac-grub`.
But, because of the way the partitions were configured, the `/boot` is not being snapshotted, so in order to copy the files of `/boot` on every Linux kernel upgrade, `rsync` will be installed.

```bash
yay -S snap-pac-grub rsync
```

There's also the possibility to enable booting the snapshots from `grub`. For that, in `/etc/mkinitcpio.conf` add `grub-btrfs-overlayfs` to the end of `HOOKS`. And don't forget to regenerate your `initramfs`:

```bash
sudo mkinitcpio -P
```

### Kernel snapshots

As said above, the `/boot` is not being snapshotted, so if an update causes instability, you'll need to restore the older kernel image. For that:

1. Create the folder `/etc/pacman.d/hooks`

```bash
sudo mkdir /etc/pacman.d/hooks
```

2. In the recently created folder, create a hook that will sync `/boot` before a kernel upgrade

```bash
sudo vim /etc/pacman.d/hooks/0-bootbackup-preupdate.hook
```

```
[Trigger]
Operation = Upgrade
Operation = Install
Operation = Remove
Type = Path
Target = usr/lib/modules/*/vmlinuz
    
[Action]
Depends = rsync
Description = Backing up /boot before updating...
When = PreTransaction
Exec = /usr/bin/rsync -a --delete /boot /.bootbackup/preupdate
```

3. Duplicate the hook to copy the new kernel after updating

```bash
sudo cp /etc/pacman.d/hooks/0-bootbackup-preupdate.hook /etc/pacman.d/hooks/95-bootbackup-postupdate.hook
```

```
[Trigger]
Operation = Upgrade
Operation = Install
Operation = Remove
Type = Path
Target = usr/lib/modules/*/vmlinuz
    
[Action]
Depends = rsync
Description = Backing up /boot after updating...
When = PostTransaction
Exec = /usr/bin/rsync -a --delete /boot /.bootbackup/postupdate
```

Reboot the system.

Now make an image for rollback to the system as it is in case something goes wrong in the near future:

```bash
sudo snapper -c root create --description “Clean BTRFS install with Snapper”
```

## Conclusion

Of course, from here there are endless possibilities for the system to be configured and since I don't have a preference yet, I'll leave it up to your creativity.

But, if you're really curious about what I do from here, you can check my [dotfiles](https://github.com/dantas15/dotfiles).

That's it! Hope you enjoyed it. Please [contact](https://www.dantas15.com/contact) me if you have any suggestions, recommendations, tips, questions or if you just want to have philosophical conversations!

## Troubleshoot

- During the installation with `pacstrap`, I received some errors about someone's signature key `is unknown trust` or `invalid or corrupted package (PGP signature)`.
  - I had to refresh the keys for it to work properly (this might take some time)

```bash
pacman-key --refresh-keys
```

## Reference

- [Arch Wiki](https://wiki.archlinux.org/) (In almost every section there are references to specific things that were being configured, make sure to check them as well)
- [Cody Hou's Arch installation with encrypt and swap](https://www.codyhou.com/arch-encrypt-swap/)