A minimal encrypted Arch Linux install

I jump around a lot between Linux (personal, mainly servers), MacOS (personal, development and laptop/desktop) and Windows (work). I also run FreeNAS but that's black magic...

As a result I'd probably consider myself fairly well-acquainted with operating systems but started feeling as though I'd become too reliant on the trusty (no pun intended) Ubuntu / Debian combination in the world of Linux and was itching to see if I could start using my lovely Mac hardware with something a bit more OpenSource friendly in keeping with my (slowly) ongoing mission to Becoming Self-sufficient and IT Resilient in 2017.

Inspired by the guys over at /r/UnixPorn I decided to take the plunge with Arch Linux in order to get a truly customised OS that reflected the hacker and tweaker in me...

Cautionary

This is a placeholder workflow that I've got for installing a minimal Arch Linux base image on an encrypted disk using LUKS + LVM. Setting up and then configuring a graphical environment is a separate - and rather personal - task I'll document later.


Installation

Assuming you've grabbed the latest image from the downloads boot up into the LiveCD image in order to install the base Arch distribution. For reference I'll be using archlinux-2017.05.01-x86_64.iso.

Arch Linux First Boot

Localisation

Before doing anything further set the keymap using
localectl set-keymap --no-convert uk as it drives me nuts later on when | etc. won't work...

Update the system clock using timedatectl set-ntp true
Running pacman -Sy will also ensure we have the most up-to-date packages
available.

Partition the drives

We are going to use the fdisk utility to create the partitions we want.

First, confirm which disk is our install target:

fdisk -l | grep Disk  
...
Disk /dev/sda: 32 GiB, 34359738368 bytes, 67108864 sectors  
Disk /dev/loop0: 369.5 MiB, 387477504 bytes, 756792 sectors  

As you can see, the LiveCD iso is mounted as a loopback device on /dev/loop0
whilst the main disk is /dev/sda.

We'll now setup and partition this disk. Edit it one by one using
fdisk /dev/sdX, replacing X with the correct letter.

This will drop you into a separate terminal prompt that you can then issue the
following commands in:

  1. n # create new partition
    • p # primary (default)
    • 1 # 1st partition (default)
    • 2048 # first sector start (default)
    • +500M # create a 500MB partition for the /boot Created a new partition 1 of type 'Linux' and of size 500 MiB.
    • a
      Selected partition 1 The bootable flag on partition 1 is enabled now.
  2. n # create new partition
    • p # primary (default)
    • 2 # 2nd partition (default)
    • select default sector # straight after 1st partition
    • select default sector # fills the remaining disk for LVM
      Created a new partition 2 of type 'Linux' and of size 31.5 GiB.
    • t # change partition type
    • 2 # 2nd partition (default)
    • 8e # LVM
      Changed type of partition 'Linux' to 'Linux LVM'.
  3. p # check partition layout before writing

    Device Boot Start End Sectors Size Id Type /dev/sda1 * 2048 1026047 1024000 500M 83 Linux /dev/sda2 1026048 67108863 66082816 31.5G 8e Linux LVM
  4. w # write to disk

We're going to format the filesystem on the boot partition now

mkfs.ext4 -L boot /dev/sda1  

Create Encrypted LVM on LUKS

Now, because I've got both a tinfoil hat and a failover tinfoil hat I'll be
installing the system to an encrypted partition and using LVM to then manage the /, /home and swap elements. This keeps everything in one place and unlocked via a single passphrase.

Using cryptsetup create an encrypted container on our Linux LVM partition.

# on a production system I'd probably also add --use-random
cryptsetup -v --cipher aes-xts-plain64 \  
    --key-size 512 --hash sha512 luksFormat /dev/sda2

Now open the container

cryptsetup open --type luks /dev/sda2 lvm  

The decrypted container is now available at /dev/mapper/lvm

Now create the LVM:

# Create a physical volume on top of the opened LUKS container:
pvcreate /dev/mapper/lvm

# Create the volume group named vgpool, adding the previously created physical
# volume to it
vgcreate vgpool /dev/mapper/lvm

# Create all your logical volumes on the volume group
lvcreate -L 4G -n swap vgpool  
lvcreate -L 8G -n root vgpool  
lvcreate -l 100%FREE -n home vgpool

# Format your filesystems on each logical volume
mkswap -L swap /dev/mapper/vgpool-swap  
swapon /dev/mapper/vgpool-swap  
mkfs.ext4 -L root /dev/mapper/vgpool-root  
mkfs.ext4 -L home /dev/mapper/vgpool-home

Run Arch installer

As we're currently still inside the LiveCD environment we need to chroot the installation such that all further commands are run on our install target disk as opposed to being discarded on reboot...

We have the following setup:

  • Primary partition for /boot on /dev/sda1
  • Encrypted LVM partition on /dev/sda2 for everything else. These are mounted on the host as:
    • /dev/vgpool/home
    • /dev/vgpool/root
    • /dev/vgpool/swap

To create the chroot we'll need to mount these within each other so the order of the below commands is important.

# mount the `/` root
mount /dev/vgpool/root /mnt

# create `/boot` directory and mount primary partition
mkdir -p /mnt/boot  
mount /dev/sda1 /mnt/boot

# create `/home` directory and mount logical volume
mkdir -p /mnt/home  
mount /dev/vgpool/home /mnt/home  

Now we'll install the Arch system to the new location.

# This will probably take a while
pacstrap /mnt base base-devel  
...
Total Download Size:   251.20 MiB  
Total Installed Size:  900.41 MiB  
...
(1/7) Updating linux initcpios
(2/7) Updating udev hardware database...
(3/7) Updating system user accounts...
(4/7) Creating temporary files...
(5/7) Arming ConditionNeedsUpdate...
(6/7) Updating the info directory file...
(7/7) Rebuilding certificate stores...
pacstrap /mnt base base-devel  32.47s user 11.13s system 3% cpu 19:11.28 total

[email protected] ~ #  

Note: If you're doing this in a VM or container for testing now is a pretty good time to take a snapshot for subsequent rollbacks... Not that you'll make any mistakes obviously.

Create a fstab for holding persistent mountpoints

genfstab /mnt >> /mnt/etc/fstab  

Perform basic Arch Linux configuration

Switch to the newly installed system with arch-chroot /mnt /bin/bash. We will install zsh last as it's not there by default :-(

zsh

# Install zsh shell
pacman -Sy zsh zsh-completions  

We can now switch to zsh with /bin/zsh

Localisation

# configure the system language by editing the `local.gen` file and
# uncommmenting: `en_GB.UTF-8 UTF-8`; and `en_US.UTF-8 UTF-8`
nano /etc/locale.gen

# now run the locale generation
locale-gen

# create /etc/locale.conf
nano /etc/locale.conf  
...
LANG=en_US.UTF-8

# set the timezone
rm /etc/localtime  
ln -s /usr/share/zoneinfo/Europe/London /etc/localtime

# now set the time standard to UTC
hwclock --systohc --utc  

Users

Update the root password with passwd. Optionally we can disable root completely.

We'll setup a new user now for administration with zsh as the default shell.

paceman -Sy sudo  # admin user will need this

# Create admin user
useradd -m -g users -G wheel,storage,power -s /bin/zsh admin  
passwd admin

# Edit sudoers
pacman -Sy vim  
visudo  
...
:e  # edit the file
...
wq!  # write changes and quit  

Networking

Set the hostname

nano /etc/hostname  
...
archer

# now also edits the `hosts file`
nano /etc/hosts  
...
127.0.1.1    archer.localdomain  archer  

Make Network connections persistent using systemctl enable dhcpcd

GRUB installation

We need to install the bootloader and then configure it to take into account
the encrypted LVM.

pacman -S grub os-prober  
grub-install /dev/sda  
grub-mkconfig -o /boot/grub/grub.cfg  

Configuring the boot loader

We need to edit mkinitcpio in order to re-generate the initial ramdisk such
that the bootloader can open the encrypted container.

nano /etc/mkinitcpio.conf  
...
HOOKS="base udev autodetect keyboard keymap consolefont modconf block encrypt lvm2 filesystems fsck"  
...
# Now re-generate the image
mkinitcpio -p linux  

In order to unlock the encrypted root partition at boot, the following kernel parameters need to be set by the boot loader:

cryptdevice=UUID=device-UUID:lvm root=/vgpool-root  
device-UUID refers to the UUID of the raw encrypted device (e.g. /dev/sdaX) You can get this with the `blkid` command on `/dev/sda2` (you need the UUID of the LUKS partition).
root If the root file system is contained in a logical volume of a fully encrypted LVM, the device mapper for it will be in the general form of `root=/dev/mapper/volumegroup-logicalvolume`

we need to edit /etc/default/grub

nano /etc/default/grub  
...
GRUB_CMDLINE_LINUX="cryptdevice=UUID=ebc2d86f-aab9-494e-a545-bfbaacce075a:lvm root=/dev/mapper/vgpool-root"  
...
# Now re-generate grub
grub-mkconfig -o /boot/grub/grub.cfg  

Post-install tweaks

As these things tend to be fault personal and dependant upon the desktop environment you're going for I've kept the below to a minimum based on what I'd always install regardless.

Package manager

Updated mirrorlists

I'm going to use the web service provided by arch for pulling back a list of all available package mirrors for a selection of European countries. This will be filtered only for those that support https and will be limited to ipv4.

# Generate https mirrorlist for European countries I trust
curl -o /etc/pacman.d/mirrorlist "https://www.archlinux.org/mirrorlist/?country=FR&country=DE&country=SE&country=CH&country=GB&protocol=https&ip_version=4&use_mirror_status=on"  
sed -i.bak 's/#//' /etc/pacman.d/mirrorlist  # remove comments  
pacman -Syy  # force refresh  

Enable AUR

su admin  # (makepkg can't be run as root)

# Install yaourt for AUR packages
pacman -S git  
cd /opt  
sudo chown -R root:wheel /opt  
sudo chmod -R g+rwx /opt  
git clone https://aur.archlinux.org/package-query.git  
cd package-query  
makepkg -si  
cd ..  
git clone https://aur.archlinux.org/yaourt.git  
cd yaourt  
makepkg -si  

James Veitch

Read more posts by this author.