Skip to content
Terencio Agozzino edited this page Sep 8, 2019 · 131 revisions

Arch Linux Icon

Create a bootable UEFI USBBefore installationSecure erasure
Disk partitioningSetup the disk encryptionSetup the LVM
Formatting the file systemsBtrfs subvolumesBase system
Setup the boot managerReboot

Installation with LVM on LUKS and Btrfs

After using Ubuntu and Debian for a while, I decided to switch to Arch Linux to provide a simple and lightweight OS. In addition, Arch Linux allows me to keep up to date with the latest versions of packages, which I greatly appreciate.

First of all, you should know that I'm willing to bring a new tutorial to bring my knowledge on some details. After reading about it, I found that the right compromise between safety and comfort was still LVM on LUKS.

The main reason for this choice of encryption is that I like to have a key to unlock all the volumes of the LVM, without going through one (or more) USB keys and risk losing them.

NOTE: don't forget that Arch Wiki remains the ultimate reference.

After this installation, you will have the following disk layout:

+----------------------------+ +-------------------------------------------------+
| EFI system partition (ESP) | | Logical volume 1       | Logical volume 2       |
|                            | |                        |                        |
| /boot                      | | [SWAP]                 | /                      |
|                            | |                        |                        |
|                            | | /dev/mapper/lvmvg-swap | /dev/mapper/lvmvg-root |
| (may be on other device)   | |-------------------------------------------------|
|                            | |                                                 |
|                            | |            LUKS2 encrypted partition            |
| /dev/nvme0n1p1             | |                 /dev/nvme0n1p2                  |
+----------------------------+ +-------------------------------------------------+

where only the ESP is not encrypted as the bootloader needs to access the /boot directory and thus load the initramfs/encryption modules needed to load the rest of the system.

Finally, the /dev/mapper/lvmvg-root logical volume will be format in Btrfs and create two sub-volume:

  1. root
  2. home

Create a bootable UEFI USB

On the assumption that:

  • X is the volume ID;
  • Y is the partition ID.

Make a FAT32 partition with boot flag

sudo fdisk /dev/sdX

Formatting the USB Flash Drive

sudo mkfs.vfat -F32 /dev/sdXY

Labeling the USB Flash Drive

sudo mlabel -i /dev/sdXY ::LABEL

Installation of Arch Linux on the USB Flash Drive

Replace archlinux by the name of your ISO image of Arch Linux:

sudo dd bs=4M if=archlinux.iso of=/dev/sdX status=progress && sync
  • bs (block size): on modern equipment (less than 5 years old), 4MB is a good bet;
  • if: source of the ISO image of Arch Linux;
  • of: destination to install the ISO image of Arch Linux;
  • status: automatically print periodic updates in the standard output.

Start on USB key

To do that, checks the following things:

  • USB Flash Drive is first on the priority of boot;
  • Secure Boot is disabled.

Before installation

Before proceeding with the installation of Arch Linux, it is important to check if you have:

  • an Internet access;
  • booted in UEFI mode or not.

Internet access

To verify that your system has Internet access, you can check it by pinging to any site (e.g. Google):

ping -c 3 www.google.com

Boot mode

To find out if you started in UEFI mode (recommended), simply check that the following command returns a list of defined UEFI variables. Otherwise, it means you have started in BIOS Legacy mode:

efivar -l

Secure erasure

Before the disk partitioning we need to avoid cryptographic attacks or unwanted file recovery. This is done by performing a secure erasure from the disk by overwriting the entire drive with random data.

NOTE: overwriting the entire drive with random data can take hours or even days, according to the size of your drive.

SSD memory cell clearing

If like me you have an SSD, consider performing a SSD memory cell clearing to minimize flash memory cache artifacts. Otherwise, I invite you to directly go to the next section.

Since I use a Lenovo ThinkPad, I have a different name for the SSD:

SSD name Commonly used SSD name
/dev/nvme0n1 /dev/sdx

Replace /dev/nvme0n1 with your SSD name.

Make sure the drive security is not frozen:
hdparm -I /dev/nvme0n1 | grep frozen

If it is indicated non frozen, then you can continue. Otherwise, I invite you to read the documentation and resolve this issue before going any further.

Enable security by setting a user password

This will allow the SSD to be locked until the next power-up cycle, denying normal access until it is unlocked with the correct password:

dparm --user-master u --security-set-pass ihateWindows /dev/nvme0n1 security_password="ihateWindows"    

NOTE: this password is only temporary because after the secure erasure, the password will be reset to NULL.

Before going any further, check that the command below displays enabled:

hdparm -I /dev/nvme0n1
Issue the ATA Secure Erase command:

Let's notify the SSD's BIOS to perform its secure erase:

dparm --user-master u --security-erase ihateWindows /dev/nvme0n1

Finally, after a successful deletion, the security of the SSD must be automatically disabled . the command below must displays enabled:

hdparm -I /dev/nvme0n1

Wipe on an empty disk

Let's fill our disk with random data to protect ourselves in order to protect ourselves against disclosure of usage patterns.

Create a temporary encrypted container on the complete device to be encrypted
cryptsetup open --type plain -d /dev/urandom /dev/nvme0n1 to_be_wiped

Once done, check that the container exists:

lsblk
Wipe the container with zeros
dd if=/dev/zero of=/dev/mapper/to_be_wiped bs=4096 status=progress

NOTE: a use of if=/dev/urandom is not required as the encryption cipher is used for randomness.

Close the temporary container
cryptsetup close to_be_wiped

Disk partitioning (UEFI)

The partitioning that follows concerns the UEFI installation. Be careful if you want to install Arch Linux in a Legacy BIOS mode.

Introduction

First of all, I have different names for the partitions, but don't be lost for so little:

Partition name Commonly used partition name
/dev/nvme0n1p1 /dev/sdx1
/dev/nvme0n1p2 /dev/sdx2

Our Arch Linux will have two partitions:

Mount point Partition name Partition type Bootable flag Suggested size
/efi /dev/nvme0n1p1 EFI System Yes 512 Mo
/ /dev/nvme0n1p2 Linux LVM No Remainder of the device

Where / will be a LVM encrypted partition having a group volume containing a physical volume and two logical volumes:

  1. swap
  2. root

Finally, as mentioned in the introduction, we will format the root volume in Btrfs and create two sub-volume:

  1. /root
  2. /home

NOTE: according to Theodore Ts'o, principal developer of ext3 and ext4 file systems, ext4 has improved features, it is not a major advance; it uses old technology and is a stop-gap. He adds that Btrfs is the best direction because "it offersimprovements in scalability, reliability and ease of management".

Without going into details, Btrfs is stable, allows for better data compression, easily handles snapshots and RAIDs.

Creation of the file system

In order to know the name of your disk, it is necessary to list the partition tables for the specified devices:

fdisk -l

Let's select our disk to build the table:

gdisk /dev/nvme0n1

Then, create a new empty GTP partition table by pressing the o key.

EFI

Partition number (1-128, default 1):
First sector (2048-2000409230, default = 2048) or {+-}size{KMGTP}:
Last sector (2048-2000409230, default = 2000409230) or {+-}size{KMGTP}: 512M
Current type is'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): ef00
Changed type of partition to 'EFI System'

/

Partition number (2-128, default 2):
First sector (1050624-2000409230, default = 1050624) or {+-}size{KMGTP}:
Last sector (1050624-2000409230, default = 2000409230) or {+-}size{KMGTP}:
Current type is'Linux filesystem'Hex code or GUID (L to show codes, Enter = 8300): 8e00
Changed type of partition to'Linux LVM'

Print the partition table

Before writing the two partitions, check that they are correct by pressing the p key.

You should have such a partition table:

Number Start (sector) End (sector) Size Code Name
1 2048 1050623 512.0 MiB EF00 EFI System
2 1050624 2000409230 953.4 GiB 8E00 Linux LVM

Write the partition table

Now that the partition table is created, all you have to do is write it to the disk by pressing the w key.

Setup the disk encryption

In order to enable disk encryption, we will first create a root LUKS volume, open it and then format it.

To keep it short, LUKS is a container format that will be used to encrypt containers, where our encryption key will be stored.

Creation of a root LUKS volume

To encrypt our / partition, we will use the cryptsetup tool:

cryptsetup --hash sha512 --use-random --verify-passphrase luksFormat /dev/nvme0n1p2
Are you sure? YES
Enter passphrase (twice)

NOTE: the majority of current CPU platforms being 64 bits, I recommend using SHA-512 which allows better performance than the SHA-256 for keys of size ≥ 256 bytes (default size for cryptsetup).

Opening the root LUKS volume as block device

The / partition being encrypted, we will open the LUKS container on /dev/nvme0n1p2 disk and name it cryptlvm:

cryptsetup luksOpen /dev/nvme0n1p2 cryptlvm
Enter passphrase

The decrypted container is now available at /dev/mapper/cryptlvm.

Setup the LVM

LVM is a logical volume manager for the Linux kernel. It is thanks to it that we can easily resize our partitions if necessary.

Create a physical volume on top of the opened LUKS container

pvcreate /dev/mapper/cryptlvm

Add the previously created physical volume to a volume group

vgcreate lvmvg /dev/mapper/cryptlvm

Create all the logical volumes on the volume group

lvcreate -L 24G lvmvg -n swap
lvcreate -l 100%FREE lvmvg -n root

NOTE: to determine the perfect size for your swap memory, refer to this table:

RAM Recommended swap space Recommended swap space for hibernation
< 2 GB 2 * RAM 3 * RAM
2 GB - 8 GB RAM 2 * RAM
8 GB - 64 GB (4 GB - 0.5 GB) * the amount of RAM 1.5 * RAM
> 64 GB ≥ 4GB hibernation not recommended

Source: RedHat's recommendation.

Formatting the file systems

As partitions are created, each of them must be formatted with an appropriate file system:

mkfs.fat -F32 /dev/nvme0n1p1
mkfs.btrfs -L btrfs /dev/mapper/lvmvg-root

Let's do the same for the swap, in addition to enabling devices and files for paging and swapping:

mkswap /dev/mapper/lvmvg-swap
swapon /dev/mapper/lvmvg-swap

Btrfs subvolumes

Subvolumes are part of the filesystem with its own and independent file/directory hierarchy, where each subvolumes can share file extents.

NOTE: a snapshot is also a subvolume, but with a given initial content of the original subvolume.

Create Btrfs subvolumes

mount /dev/mapper/lvmvg-root /mnt
btrfs subvolume create /mnt/root
btrfs subvolume create /mnt/home
umount /mnt

Mounting Btrfs subvolumes

mkdir /mnt/{boot,home}

SSD_MOUNTS="autodefrag,compress=lzo,discard,inode_cache,noatime,nodev,rw,space_cache,ssd"
mount -o subvol=root,$SSD_MOUNTS /dev/mapper/lvmvg-root /mnt
mount -o subvol=home,$SSD_MOUNTS,nosuid /dev/mapper/lvmvg-root /mnt/home

mount -o discard,noatime,nodev,noexec,nosuid,rw /dev/nvme0n1p1 /mnt/boot

Small details on the options given with the -o flag:

  • autodefrag: enable automatic file defragmentation for small random writes in files with a maximum file size of 64K.
  • compress=lzo: compresses files with the lzo type which is a lossless data compression algorithm that is focused on decompression speed.
  • discard: enable discarding of freed file blocks using TRIM operation (useful for SSD devices).
  • inode_cache: enable free inode number caching (may cause an overflow problem when the free space checksums do not match one page).
  • noatime: allows measurable performance gains by eliminating the need for the system to write to the file system for files that are simply read.
  • nodev: disallows creating and accessing device nodes (used in particular for special files in /dev).
  • noexec: does not allow the execution of executable binaries in the mounted file system.
  • nosuid: specifies that the filesystem cannot contain set userid files.
  • rw: allows reading and writing.
  • space_cache: control the free space cache. This greatly improves performance when reading block group free space into memory.
  • ssd: by default, Btrfs will enable or disable SSD allocation heuristics depending on whether a rotational or non-rotational device is in use.

NOTE: some of these options are not useful to you if you don't use an SSD.

Base system

Installation of the packages onto a given root file system

pacstrap /mnt base base-devel btrfs-progs dialog wireless_tools wpa_supplicant --no-confirm

Small details about the given packages to pacstrap:

  • base and base-devel: package groups which include basic libraries like gcc and linux.
  • btrfs-progs: userspace utilities to manage btrfs filesystems.
  • dialog: tool to display dialog boxes from shell scripts (useful for wifi-menu).
  • wireless_tools: tools allowing to manipulate the Wireless Extensions.
  • wpa_supplicant: support for WEP, WPA and WPA2.

Configuration of the system

In this section, we will configure the system base in order to have a decent environment.

Generate an fstab file
genfstab -U /mnt >> /mnt/etc/fstab
Change root into the new system
arch-chroot /mnt
Set the time zone
ln -sf /usr/share/zoneinfo/Europe/Brussels /etc/localtime

Generate /etc/adjtime:

hwclock --systohc
Localization

Replace en_US by your location in the next command and execute it.

sed -i '/en_US.UTF-8 UTF-8/s/^#//g'

Generate the locales:

locale-gen

Set the LANG variable in /etc/locale.conf:

echo "LANG=en_US.UTF-8" >> /etc/locale.conf
Network configuration

In this example, the computer hostname is ThinkPad. Replace it with whatever you like.

echo ThinkPad > /etc/hostname

Add matching entries to /etc/hosts:

echo "127.0.0.1  localhost" >> /etc/hosts
echo "::1        localhost" >> /etc/hosts
echo ":127.0.1.1 ThinkPad.localdomain  ThinkPad" >> /etc/hosts
Set the root password
passwd
Create an initial ramdisk environment
nano /etc/mkinitcpio.conf

When using the ramdisk environment, it is necessary to take into account LVM, Btrfs support and others.

  1. Add vfat aes_x86_64 in the MODULES section.

  2. Add encrypt lvm2 resume in the HOOKS section before filesystems.

  3. Remove fsck from the HOOKS section: Thus, systemd will fsck all filesystems having a fsck pass number greater than 0 (either from /etc/fstab or a user-supplied unit file).

  4. Add btrfs at the end of HOOKS.

To summarize, you must have this in your MODULES and HOOKS sections:

MODULES=(vfat aes_x86_64)
HOOKS=(base udev autodetect modconf block encrypt lvm2 resume filesystems keyboard btrfs)

Finally, recreate the initramfs image:

mkinitcpio -p linux

Setup the boot manager

Since we have an EFI system and we will probably not use all the features of GRUB, we will install systemd-boot for our simple UEFI boot manager that executes configured EFI images.

We are going to use systemd-boot, previously called gummiboot, for our simple UEFI boot manager that executes configured EFI images.

Set the path to the Extended Boot Loader partition

bootctl --path=/boot install

Configuring the loader

default  arch
timeout  0
console-mode max
editor   no

Small details about the given parameters entered:

  • default: default entry to select.
  • timeout: menu timeout in second, useful to allow people who have multiple operating systems.
  • console-mode: changes UEFI console mode.
  • editor: whether to enable the kernel parameters editor or not. Strongly recommended to set this option to no to avoid bypass root password and gain root access.

Adding the loader

To add the loader, it is necessary to distinguish 2 cases:

  1. For AMD processors the microcode updates are available in linux-firmware, which is installed as part of the base system.
  2. For Intel processors, it is necessary to install the intel-ucode package and add the line initrd /intel ucode.img as shown below:
sudo pacman -S intel-ucode

echo "title   Arch Linux" > /boot/loader/entries/entry.conf
echo "linux   /vmlinuz-linux" >> /boot/loader/entries/entry.conf
echo "initrd  /intel-ucode.img" >> /boot/loader/entries/entry.conf
echo "initrd  /initramfs-linux.img" >> /boot/loader/entries/entry.conf
echo "options cryptdevice=UUID=...:lvm:allow-discards root=/dev/mapper/lvmvg-root rootfstype=btrfs rootflags=subvol=root resume=/dev/mapper/lvmvg-swap quiet rw

Where the UUID in cryptdevice corresponds to the UUID of the encrypted root (for my case: /dev/nvme0n1p2), obtained by the blkid command:

blkid /dev/nvme0n1p2 -s UUID -o value

Small details about the given parameters entered:

  • title: operating system name.
  • linux: path to vmlinuz (statically linked executable file that contains the Linux kernel).
  • initrd: path to initramfs.
  • options: command line options to pass to the EFI program or kernel parameters.

Small details about the options given to the cryptdevice:

  • allow-discards: enables TRIM support on the SSDs.
  • rootfstype: root file system type.
  • resume: allows you to resume after suspending the computer from the disk, keeping the swap space intact.

Reboot

Congratulations, we are ready for a first reboot, don't forget to remove installation media:

exit
umount -R /mnt
reboot

Clone this wiki locally