Arch Linux Hardened Installation Guide

· 11min · Joe Lopes

I have decided to install Arch Linux on my next laptop but first had to test it to be sure of my choice. Since I was looking for a hardened installation, which was not covered by the official installation guide, I decided to create this guide for my personal use and I hope it will be useful to someone else.

This text will consider the installation in a VirtualBox VM.

Installer Setup

Assuming you already have the official ISO, create a new VM in VirtualBox with the following characteristics --or very similar:


  • RAM: 4096 MB
  • Enable EFI


  • Video memory: 128MB


Turning the VM on should load the ISO and present the shell, which is the installation's start point --using the EFI mode, it took ≈2' for the shell appearing.

The first thing to do is to prepare this installation environment, assuring that the keyboard and connectivity are properly configured.


In my case, I use a US keyboard, but it is essential for me to use Latin characters, such as àêíöú --if this set of characters isn't necessary, this step is needless. The commands below helped me to find candidates to layout and apply the correct one:

localectl list-keymaps | egrep '(us|uk)'  # to find layouts
loadkeys us-acentos                       # load the selected layout


The network should be accessible just as the system's up, but here I list some commands that can help to troubleshoot it.

ip link
ip address
dhcpcd enp0s3  # enable dhcp for enp0s3 interface

Having connectivity working, enable NTP to make sure the clock is synchronized with reliable sources.

timedatectl set-ntp true
timedatectl status

Disk Preparation

These steps will show how to perform full device encryption using LVM, enabling the disk to receive the new system.


The main goal here is to create only a minimum bootable unencrypted partition and an encrypted partition on the rest of the disk. Table 1 resumes this scenario.

Mount pointPartitionSizeFile system
/efiprimary550 MBFAT32
/bootprimary450 MBEXT4

When using EFI, it is necessary to create another partition to mount the /efi directory and this partition must be formatted using FAT32 --personally, I recommend to allocate 550 MB for it.

You can use cfdisk for partitioning, but this tutorial will present the fdisk commands.

fdisk -l         # list the available disks
fdisk /dev/sda   # start partitioning /dev/sda

## inside fdisk...
n > p > default > default > +550M    # [n]ew [p]rimary partition with 550 MB
n > p > default > default > +450M    # [n]ew [p]rimary partition with 450 MB
n > p > default > default > default  # [n]ew [p]rimary partition with the left space
w                                    # [w]rite changes and exit


LUKS will be used to encrypt the system's partition and this is done in the next command list. Note that after running the first command you will be asked to insert a password and must be aware to insert a strong one. This password will always be asked on the system boot.

The second command will open this newly encrypted partition as a new device in /dev/mapper/luks.

cryptsetup -v --type luks --cipher aes-xts-plain64 --key-size 256 --hash sha256 --iter-time 2000 --use-urandom --verify-passphrase luksFormat /dev/sda3

cryptsetup luksOpen /dev/sda3 luks


The encrypted partition will host the LVM system with the partitions shown in Table 2 --these are the partitions I like to use in my systems and the spaces are dimensioned to this 16 GB disk.

Mount pointPartition typeSizeFile system
swapprimary512 MBswap
/primary6 GBEXT4
/homeprimary6 GBEXT4

The next command listing shows all commands needed to create LVM volumes for each partition. The last command is optional but is good to check if everything's fine.

pvcreate /dev/mapper/luks
vgcreate vg0 /dev/mapper/luks

lvcreate --size 512M vg0 --name swap
lvcreate --size 6G vg0 --name root
lvcreate --size 6G vg0 --name home
lvcreate -l +100%FREE vg0 --name var



With all partitions in place, they should be formatted as previously planned. The next listing shows all commands to accomplish this task --the last one just presents a resume of everything.

mkswap /dev/mapper/vg0-swap
mkfs.fat -F32 /dev/sda1
mkfs.ext4 /dev/sda2
mkfs.ext4 /dev/mapper/vg0-root
mkfs.ext4 /dev/mapper/vg0-home
mkfs.ext4 /dev/mapper/vg0-var

lsblk  # just to see the big picture


Finally, all partitions must be mounted, including those inside the root partition and the swap.

swapon /dev/mapper/vg0-swap

mount /dev/mapper/vg0-root /mnt
mkdir /mnt/{boot,home,var}

mount /dev/sda2 /mnt/boot
mkdir /mnt/boot/efi

mount /dev/sda1 /mnt/boot/efi
mount /dev/mapper/vg0-home /mnt/home
mount /dev/mapper/vg0-var /mnt/var


At this point, the disk should be ready to receive the system's files. To do it, pacman will be used, but since it comes with a lot of repositories and many of them could perform really bad for some users, it is recommended to allow only the nearest from the user. I use two simple commands to discard all repositories but the ones in the countries I selected:


2021-10-26: This step failed when I installed Arch today because the mirrorlist file format changed, but it can be avoided without further problems.

cp /etc/pacman.d/mirrorlist /etc/pacman.d/mirrorlist.bkp

sed -n '/\(Brazil\|United States\)/,+1p' /etc/pacman.d/mirrorlist.bkp > /etc/pacman.d/mirrorlist

Now the system can be installed with the next command --notice that I'm installing additional packages I use, but most users will only want the first three --base, linux, and linux-firmware.

pacstrap /mnt base linux linux-firmware \
    ufw sudo man atop p7zip zip unzip unarchiver \
    bash-completion zsh zsh-completions tmux \
    vim dnsutils mtr wget curl git python

Now that all files are in place it is time to create the /etc/fstab file that will implement the mounted partitions.

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

Edit /etc/fstab to insert some security options, including a few more transient partitions that will exist only in memory. First add the nodev option in /home line, then create the lines below at the end of file.

tmpfs /var/tmp tmpfs size=1G,mode=1777,rw,nodev,nosuid,noexec 0 0
tmpfs /tmp     tmpfs size=1G,mode=1777,rw,nodev,nosuid,noexec 0 0
tmpfs /dev/shm tmpfs size=1G,rw,nodev,nosuid,noexec           0 0

At this point, you should have a virtual environment running in memory --which you are using to install the system-- and a Linux system installed on the disk mounted in /mnt. Now just chroot to /mnt to create the basic configuration for it.

arch-chroot /mnt


Inside the installed system, the localization settings should be created to appropriately define timezone, idioms, and the keyboard. Starting with the timezone, the next listing shows the commands --substitute the time zone accordingly.

ln -sf /usr/share/zoneinfo/America/Sao_Paulo /etc/localtime
hwclock --systohc

I do mix en_US and pt_BR as locales, but always in UTF-8. To create a similar setup --even if only one locale will be used--, uncomment the language lines in the /etc/locale.gen file and generate the locales.

Generate the locales using the command locale-gen and create the /etc/locale.conf file using the next listing as example.


To configure the keyboard, just create the /etc/vconsole.conf file and set the same keyboard layout you are using for the installation --considering you changed the default at the beginning.

echo "KEYMAP=us-acentos" > /etc/vconsole.conf


Networking setup includes creating the hostname files and enabling DHCP service --this last step is not necessary if you pretend to use a static IP approach, but it is up to you.

Start by creating the /etc/hostname file with your own setting --see the next command.

echo "orion" > /etc/hostname

Add the next lines to the /etc/hosts file matching the last line with the name used in the previous command.   localhost
::1         localhost  orion

Since my hypervisor uses DHCP, makes sense to be sure this service will be enabled after rebooting the system. I prefer to use the Arch Linux's default network manager, the systemd-networkd. First create the file /etc/systemd/network/ and insert the content from the next listing, assuming you are setting up a wired interface named enp0s3 --you can list all available interfaces with the command networkctl list.



Enable the service so it will run after rebooting the system.

systemctl enable systemd-networkd.service

2021-10-26: Cloudflare's DNS is a better option: and than Google's.

Add Google DNSs in /etc/resolv.conf.



This is not a necessary step at all, but the root user should be avoided for security reasons in any operating system. So, I will create a user (lopes) and allow him to use Sudo --note that my default shell is zsh. Strong passwords must be defined for both users.

The next commands show how to set the password for root and create your own user.

passwd  # set root password

useradd -m -G wheel,audio,video,optical,storage -s /bin/zsh lopes
passwd lopes

Use the visudo command to open the Sudo's configuration file, then find and uncomment the line below.

%wheel ALL=(ALL) ALL

Boot Loader

The last step is to install and configure the boot loader, ensuring that the LVM and encrypted partition will be recognized. For doing this, GRUB and mkinitcpio must be adjusted as shown in the following listing.


After installing the package, it must be installed in the boot device and configuration must be created. Then, the default configuration file must be changed because the variable GRUB_CMDLINE_LINUX should contain the command line to load the encrypted device and the variable GRUB_ENABLE_CRYPTODISK must be set to "yes".

Three packages must be installed before proceeding, so run the next commando to do it.

pacman -S grub efibootmgr lvm2


This Arch script must be properly configured to support the file systems, so module ext4 should be loaded and hooks encrypt and lvm2 must be loaded before filesystems. Open the /etc/mkinitcpio.conf file in a text editor and add the ext4 in the modules line. Then, find the hooks line and add the modules encryption and lvm2 before the filesystems, as shown in the next listing.

HOOKS=(...encrypt lvm2 filesystems...)

Open GRUB's /etc/default/grub file, add the encryption settings to the GRUB_CMDLINE_LINUX and uncomment the GRUB_ENABLE_CRYPTODISK line as in the next listing.

GRUB_ENABLE_CRYPTODISK=y   # uncomment this line

Now, execute the commands below to recreate the initial ramdisk environment with all the necessary support and to create the GRUB's configuration files.

mkinitcpio -p linux

grub-install --target x86_64-efi --bootloader-id arch --efi-directory /boot/efi
grub-mkconfig -o /boot/grub/grub.cfg

The next listing demonstrates how to configure EFI fallback.

mkdir /boot/efi/EFI/boot
cp /boot/efi/EFI/arch/grubx64.efi /boot/efi/EFI/boot/bootx64.efi

Create the file /boot/efi/startup.nsh and insert the lines from the next listing there.

bcf boot add 1 fs0:\EFI\arch\grubx64.efi "Orion Bootloader"


The system must be fully functional at this point, so it is time to remove the installation media and boot the system. Run the following commands to get out from the chroot environment, make sure that the disk is properly unmounted, and reboot the system.

umount -R /mnt
swapoff -a

After rebooting you will be asked to enter the password to decrypt the disk and after that, the system will be loaded, presenting you the login prompt. At this point, you are able to go ahead and customize the system as you wish and install further packages.

Let's rock and roll in Arch!