Installing Arch Linux - Stanislav Senotrusov

36 min read Original article ↗

Preface

Arch uses a manual installation process instead of a guided setup. You build the OS from the ground up using the command line, giving you total control over the environment. Because there's no automation, every configuration choice is yours, making the entire system much easier to troubleshoot and understand.

The Arch Wiki is the primary resource for learning which commands to run and how the system components fit together. It is a well-maintained, massive collection of up-to-date information. Specifically, the Installation guide outlines the core steps for getting a functional system up and running.

Because Arch encourages you to make your own choices, the process usually requires quite a bit of research. This guide is the result of that research: it is a set of lab notes documenting my specific path, the commands I used, and the reasoning behind them. I wrote it to keep my own installations reproducible without losing the context of why I made certain decisions.

While I originally built this for my own workstations, the setup is generic enough to work for most machines. It results in a minimal, reasonably secure system suitable for daily use.

I've consolidated these decisions into ready-to-run command sequences. Feel free to follow them exactly or just use them as a starting point for your own configuration.

This guide provides flexible options for:

  • Full-disk encryption (optional)
  • Root file system selection (ext4 or Btrfs)
  • NVIDIA driver installation
  • Modular package presets

Beyond the base install, it also covers practical configuration steps like:

  • Enabling SSH during the install for remote access and easier copy-pasting
  • Aligning NVMe drives to 4K sectors
  • Enabling TRIM support for encrypted drives
  • Setting up a clean partition layout with parted
  • Using a swap file instead of a partition
  • Configuring systemd-boot
  • Configuring networking with systemd-networkd and Wi-Fi connections with iwd
  • Installing an AUR helper

This guide is dual-licensed under the Apache License, Version 2.0 and the MIT License. You can choose to use it under the terms of either license. Please note that all contributions must be provided under both licenses.

If you have improvements, corrections, or updates, feel free to submit a pull request. You are also welcome to fork this guide if your requirements are different.

This document does not replace the official Installation Guide, which remains the definitive reference.

Data loss warning

This guide includes steps that will erase all data on your disk. Modify the disk preparation, partitioning, and formatting steps if you intend to preserve existing data.

If you have access to a second computer, the most convenient way to install Arch is to boot the target machine from a flash drive and connect to it via SSH from the other computer. This approach allows you to keep this documentation open and copy commands easily between systems. Instructions for enabling SSH on the live environment are included below.

You can also complete the installation directly on the target machine if you prefer working locally.

Safe use of shell variables

This guide uses parameter expansion syntax, such as ${target:?}, to prevent unintended command operation if a variable is unset or empty. This safety check is particularly useful when copying commands over SSH or when several shell tabs are open, as it reduces the chance of running a command with incomplete parameters.

For manual input, you may simplify variable references to $target. However, ensure that every variable is correctly assigned and contains the expected value before running any command.

Download the Arch ISO and write it to a USB drive

This section assumes you are using a Linux computer to create the bootable installation medium. If you are on Windows, macOS, or Android, refer to the USB flash installation medium article. The Arch ISO file and additional download options are available on the Arch Linux Downloads.

Download the ISO

Use curl to fetch the latest installation image from a reliable mirror. Arch Linux releases a new ISO every month.

curl -O https://geo.mirror.pkgbuild.com/iso/latest/archlinux-x86_64.iso

Verify the SHA256 checksum

Verify the SHA256 hash to ensure the downloaded file matches the official signature and has not been tampered with.

This method relies on the Arch Linux download page to securely provide the correct checksum.

curl --silent --show-error "https://archlinux.org/download/" |
  grep -E --only-matching "SHA256.*[a-f0-9]{64}" |
  awk 'NR==1' |
  sed -E 's/SHA256.*([a-f0-9]{64})/\1  archlinux-x86_64.iso/' |
  sha256sum --check -

If the output is archlinux-x86_64.iso: OK, the file is valid.

One-liner limitations

Although this one-liner is convenient, changes to the download page formatting may prevent it from retrieving the correct checksum. If you encounter issues, use the manual method.

Visit the Arch Linux download page and copy the SHA256 hash for the ISO.

Replace SIGNATURE with the copied hash, then verify the file.

sha256sum --check <(echo SIGNATURE archlinux-x86_64.iso)

If the output is archlinux-x86_64.iso: OK, the file is valid.

Write the ISO to a USB drive

Begin by identifying the USB device you plan to use. After verifying the correct device, store its path in a variable so you can safely proceed with creating the bootable drive.

You can locate the device with either lsblk or fdisk. The lsblk command provides detailed information, while fdisk offers a shorter summary.

Display the connected physical devices.

lsblk --nodeps --paths --output NAME,SIZE,TRAN,MODEL,REV,SERIAL

Then view the same devices again with expanded partition and filesystem details.

lsblk --paths --output NAME,SIZE,TYPE,MOUNTPOINTS,FSTYPE,LABEL,UUID,PARTTYPENAME,PARTLABEL

List the available disks and partitions.

All data on the selected device will be lost

The device you choose will be completely erased in the following steps. Double check your selection to avoid unintended data loss.

Once you have confirmed the correct device, assign its path to a variable. Replace sdX with the actual device name of your USB drive.

Finally, use dd to write the ISO image to the device.

sudo dd if=archlinux-x86_64.iso of="${flash:?}" bs=4M status=progress oflag=sync
Verify the USB copy (optional)

To ensure the data was written correctly, compare the written data byte-by-byte with the original ISO file.

sudo dd if="${flash:?}" iflag=direct,count_bytes count="$(stat -c %s archlinux-x86_64.iso)" bs=4M status=progress | cmp - archlinux-x86_64.iso && echo VERIFIED || echo ERROR

Boot from USB flash drive

Access your system's firmware (BIOS/UEFI) settings to select the USB drive as the boot device.

The USB drive can be safely removed once the live environment loads to a shell prompt.

Secure Boot is not supported

The official Arch Linux installation images do not support Secure Boot, so it must be disabled to boot the installer. Enabling Secure Boot on the installed system is an advanced topic and is not covered in this guide. If required, consult the Secure Boot page.

Improve console readability

Change the console font for better legibility, especially on high-resolution displays. This sets the Terminus font with a Western European codepage and bold weight. Choose the font size that suits your needs.

setfont ter-124b  # 24-pixel height
setfont ter-128b  # 28-pixel height
setfont ter-132b  # 32-pixel height

Connect the installation environment to the network

A reliable network connection is required during installation, as packages are downloaded directly from remote mirrors.

  • Wired connections usually work automatically through DHCP. If an Ethernet cable is connected, the system is likely already online.
  • Wireless connections require additional setup. Follow the steps in the section below to configure Wi-Fi.
  • Mobile broadband connections, such as USB modems, are also supported. Refer to the Mobile broadband modem wiki page for detailed instructions.
Connect to the WiFi network

Start the interactive iwctl tool.

Once inside iwctl, you will see a prompt that begins with [iwd]#. You can use the Tab key to auto-complete commands, device names, and network names.

List available devices to identify your wireless interface name, for example wlan0.

Scan for networks and display the results. Replace wlan0 with the device name identified in the previous step.

station wlan0 get-networks

Connect to your SSID. If the network is secured, iwctl will prompt you to enter the password securely.

station wlan0 connect YOUR_NETWORK_SSID

Verify the connection status. You should see connected under State, your SSID under Connected network, and an assigned IPv4 address.

Exit iwctl when finished.

Verify network connectivity

Before continuing, confirm that the live environment has internet access.

ping -c 3 ping.archlinux.org

Access the installation environment remotely via SSH (optional)

You can use SSH to access the Arch Linux live environment from another machine. This is optional, but it can make the installation process more convenient by allowing copy and paste, quick access to documentation, and the ability to work from a more comfortable system while the installer runs on the target hardware.

Connect to the live environment

To allow SSH access, set a temporary root password in the Arch Linux live environment. This password is only valid for the live session and is discarded after installation.

If your client machine, meaning the system you are connecting from, supports mDNS, you can connect using the default hostname archiso.local. Otherwise, connect using the IP address assigned to the live environment.

Run the following command on the client machine to connect to archiso.local.

ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@archiso.local

First, determine the IP address of the live environment.

Then, on the client machine, use that IP address to connect, replacing IP_ADDRESS with the actual value.

ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -l root IP_ADDRESS

Perform basic system checks

Confirm UEFI boot mode

Confirm the system booted in UEFI mode, which is required for systemd-boot.

cat /sys/firmware/efi/fw_platform_size

If the file exists and contains 64, the system is in 64-bit UEFI mode. If the file is absent, reboot the system and switch to UEFI mode in the firmware settings.

Check system time

Verify the current time and that NTP synchronization is active.

The time zone set here only affects the live environment and will be configured for the installed system later.

Assign variables for disk identification

Identify the target disk by listing available block devices and assign the device path and partition names to shell variables.

You can locate the device with either lsblk or fdisk. The lsblk command provides detailed information, while fdisk offers a shorter summary.

Display the connected physical devices.

lsblk --nodeps --paths --output NAME,SIZE,TRAN,MODEL,REV,SERIAL

Then view the same devices again with expanded partition and filesystem details.

lsblk --paths --output NAME,SIZE,TYPE,MOUNTPOINTS,FSTYPE,LABEL,UUID,PARTTYPENAME,PARTLABEL

List the available disks and partitions.

All data on the selected disk will be lost

The device you select will be completely erased in the following steps. Choose carefully to avoid data loss. Back up all necessary data.

Use the appropriate tab for your disk type.

Replace /dev/nvme0n1 with the NVMe device you want to use, and assign the partition names to variables.

target=/dev/nvme0n1
efi="${target:?}p1"
root_physical="${target:?}p2"
root_actual="${root_physical:?}"

Replace /dev/sda with the SATA device you want to use, and assign the partition names to variables.

target=/dev/sda
efi="${target:?}1"
root_physical="${target:?}2"
root_actual="${root_physical:?}"

The root_actual variable is initially set to the physical root partition and will be updated later if LUKS encryption is applied.

Check disk settings

Ensure 4K block size on NVMe drives

Aligning your NVMe drive to a 4K (4096 bytes) logical sector size, if supported, improves performance and durability.

Destructive operation with potential hardware risk

This operation is destructive and will erase all data on the drive. It has also been observed that some NVMe drives become unresponsive after formatting and require a system reboot before they operate again (although the new format will be applied afterward). It is also reasonable to assume that some drives may become unusable due to firmware bugs, as very few users ever change the factory default format. You likely do not want to be the first to discover such an issue, so proceed with caution and carefully consider whether reformatting is worth the risk. It is perfectly fine to stay with the manufacturer's default format, even if it offers slightly lower performance, in exchange for peace of mind.

First, check the current logical sector size.

Next, verify the supported LBA formats to determine the optimal FORMAT_ID.

Examine the Supported LBA Sizes list at the end of the output.

smartctl --capabilities "${target:?}"

Check the LBA Format list at the end of the output.

nvme id-ns --human-readable "${target:?}"

If a 4K format is supported but not active, reformat the drive to the optimal LBA Format ID.

nvme format --lbaf=FORMAT_ID "${target:?}"

Verify TRIM support

Verify TRIM support, which allows the OS to communicate unused data blocks to a Solid State Drive (SSD) to maintain performance and lifespan. Non-zero values for DISC-GRAN and DISC-MAX confirm that TRIM support is present.

lsblk --discard "${target:?}"

Create partitions

The plan is to create a ~1 GiB EFI system partition for boot files and use the remaining space for the root partition. Swap will later be added as a regular file within the root filesystem to keep the layout flexible.

Launch parted for interactive partitioning.

Create a GPT partition table

Create a GPT (GUID Partition Table), the modern standard required for UEFI.

Set the unit to MiB for optimal alignment

Set the unit to mebibytes (MiB) so that any values passed to mkpart are interpreted in this unit. Doing this first ensures partitions land on precise mebibyte boundaries, which avoids alignment problems and improves performance. Because the default parted unit is less exact, explicitly selecting MiB helps prevent unintended offsets.

Create the EFI system partition

Create a FAT32 partition that occupies the space from 1 MiB up to the chosen alignment point, which comes out to roughly 1.10 GiB.

Rationale for the 1152 MiB alignment point

Modern high-density TLC and QLC flash devices that use 3-bit cells and multi-plane layouts often have erase block sizes divisible by three, such as 24 MiB, 48 MiB, or 96 MiB.

Given that a boot partition typically needs about 1 GiB, a natural question arises: where should the root partition begin?

The 1152 MiB mark serves as a convenient common multiple that aligns cleanly with both traditional binary-oriented block sizes (such as 16 or 32 MiB) and newer ternary-based patterns. The following JavaScript snippet shows how evenly it divides into current and plausible future erase block sizes.

[4, 8, 16, 24, 32, 48, 96, 128, 192].map(i => 1152 / i)

This assumes, of course, that filesystems arrange data in ways that respect the alignment constraints imposed by the hardware, which remains outside our control.

If you are using an encrypted partition with LUKS2, keep in mind that it adds its own header, typically 16 MiB. Subtract this amount from the 1152 MiB alignment target.

As a side note, the boot partition is fine with 1 MiB alignment since it is rarely written.

Set the ESP flag

Mark the first partition as the EFI System Partition, which is necessary for UEFI bootloaders.

Create the root partition

Create the root partition using all remaining disk space, starting immediately after the ESP.

Check partition alignment

Verify optimal alignment for partition 1.

Verify optimal alignment for partition 2.

Review and exit

Display the partition table to verify the final layout.

Exit parted.

Configure disk encryption

Choose whether to encrypt the root partition with LUKS or proceed without encryption.

Understanding disk encryption

Disk encryption is a broad topic with many configuration options and security trade-offs. While this guide covers one possible approach, you can always dive deeper into the various methods and implementation details using the extensive dm-crypt page on the Arch Wiki.

Configure disk encryption

If you choose to encrypt the root partition $root_physical with LUKS2, the decrypted device becomes $root_actual.

Format the root partition with LUKS2

Format the root partition ($root_physical) using LUKS2. The --sector-size 4096 option aligns encryption with 4K physical sectors, which improves performance on modern drives.

When prompted, choose a strong passphrase and store it safely. Losing the passphrase means losing access to all encrypted data.

cryptsetup luksFormat --batch-mode --verify-passphrase --type luks2 --sector-size 4096 "${root_physical:?}"

Open the LUKS container and set persistent options

Open the encrypted partition and map it as /dev/mapper/luks-root. The performance and discard options enabled here apply automatically for future unlocks.

cryptsetup --perf-no_read_workqueue --perf-no_write_workqueue --allow-discards --persistent open "${root_physical:?}" luks-root

Set the root_actual variable

Update the variable so that subsequent filesystem operations target the decrypted container.

root_actual="/dev/mapper/luks-root"

No action is required for this step when not using LUKS encryption. The $root_actual variable, which represents the device path for the root filesystem, retains its initial value of $root_physical.

Format and mount file systems

Format the partitions with the chosen filesystems and mount them to the installation directory (/mnt).

Root partition

Choose either the traditional ext4 filesystem or Btrfs. Ext4 is a traditional, robust, and mature filesystem. Btrfs provides checksums and supports subvolumes and snapshotting for flexible organization.

Create an ext4 filesystem on the partition.

mkfs.ext4 "${root_actual:?}"

Mount the root partition to /mnt.

mount -o noatime,commit=30 "${root_actual:?}" /mnt

The noatime option improves performance by disabling file access time updates, and the commit=30 option sets the maximum time (in seconds) that data is held in memory before being written to disk, balancing data loss risk and I/O performance.

Info

See the ext4 guide for more information.

Format the partition as Btrfs.

mkfs.btrfs "${root_actual:?}"

Temporarily mount the top-level filesystem to create a commonly adopted Btrfs subvolume layout (@ for root, @home, and @swap).

mount "${root_actual:?}" /mnt
btrfs subvolume create /mnt/@
btrfs subvolume create /mnt/@home
btrfs subvolume create /mnt/@swap
umount /mnt

Mount the subvolumes at their final mount points.

mount -o noatime,flushoncommit,subvol=/@ "${root_actual:?}" /mnt
mount --mkdir -o noatime,flushoncommit,subvol=/@home "${root_actual:?}" /mnt/home
mount --mkdir -o noatime,flushoncommit,subvol=/@swap "${root_actual:?}" /mnt/swap

The noatime option improves performance by disabling file access time updates, and flushoncommit prioritizes data integrity.

Info

See the Btrfs guide for details on Btrfs usage and subvolume setup.

EFI system partition

Format the ESP as FAT32, which is required for UEFI booting.

mkfs.fat -F 32 -S 4096 "${efi:?}"

Mount the ESP partition to /mnt/boot with secure permissions (umask=0077) to protect the boot files.

mount --mkdir -o noatime,umask=0077 "${efi:?}" /mnt/boot

Verify mounts

Verify that all partitions, including subvolumes, are correctly mounted under /mnt.

Install essential packages

Select your CPU architecture below and run the corresponding code block in your shell to initialize the packages array. This array includes the kernel, firmware, boot manager tools, essential utilities, and the correct CPU microcode package.

Define the base system

packages=(
  amd-ucode         # CPU microcode updates for AMD processors
  base              # Minimal base system required for a functional Arch installation
  efibootmgr        # Tool for managing UEFI boot entries
  intel-ucode       # CPU microcode updates for Intel processors
  linux             # The Linux kernel
  linux-firmware    # Firmware files required by many hardware devices
  man-db            # Backend for the manual page system
  man-pages         # Official Linux manual pages
  nano              # Simple terminal-based text editor
  sudo              # Privileged command execution for non-root users
  terminus-font     # Readable monospaced console font
  )
packages=(
  base              # Minimal base system required for a functional Arch installation
  efibootmgr        # Tool for managing UEFI boot entries
  intel-ucode       # CPU microcode updates for Intel processors
  linux             # The Linux kernel
  linux-firmware    # Firmware files required by many hardware devices
  man-db            # Backend for the manual page system
  man-pages         # Official Linux manual pages
  nano              # Simple terminal-based text editor
  sudo              # Privileged command execution for non-root users
  terminus-font     # Readable monospaced console font
  )
packages=(
  amd-ucode         # CPU microcode updates for AMD processors
  base              # Minimal base system required for a functional Arch installation
  efibootmgr        # Tool for managing UEFI boot entries
  linux             # The Linux kernel
  linux-firmware    # Firmware files required by many hardware devices
  man-db            # Backend for the manual page system
  man-pages         # Official Linux manual pages
  nano              # Simple terminal-based text editor
  sudo              # Privileged command execution for non-root users
  terminus-font     # Readable monospaced console font
  )

Add optional packages

Append optional packages to the packages array as needed for your system, such as development tools, desktop software, networking components, drivers, and file system utilities.

AUR and development tools

Install these packages only if you plan to use the Arch User Repository (AUR). Instructions for installing an AUR helper are provided later in this guide.

packages+=(
  git                # Distributed version control system
  base-devel         # Basic tools to build Arch Linux packages
)
Web browser and essential desktop fonts

Recommended for most desktop systems. A web browser is required for everyday use, and the Noto font family provides broad language and emoji coverage with consistent rendering.

packages+=(
  firefox            # Graphical web browser
  noto-fonts         # Primary Unicode font family
  noto-fonts-cjk     # Chinese, Japanese, and Korean font support
  noto-fonts-emoji   # Emoji font for full emoji rendering
)
GNOME desktop environment

Install these packages to set up a modern graphical desktop with built in networking support.

packages+=(
  gnome              # Full GNOME desktop environment
  networkmanager     # Network connection management service
)
iwd wireless networking daemon

If you plan to install GNOME with NetworkManager, you generally do not need iwd unless you specifically want to reconfigure NetworkManager to use it as the Wi-Fi backend.

If you prefer to manage networking manually, for example with systemd-networkd, you may want to install iwd. It is a modern, lightweight wireless networking daemon. You may also want to install impala, a terminal interface for scanning, connecting to, and managing wireless networks with iwd.

A later section explains how to configure iwd to work with systemd-networkd.

packages+=(
  iwd                # Wireless network management daemon
  impala             # TUI wireless network manager and frontend for iwd
)
systemd-resolved system DNS resolver

Install this package only if you plan to use systemd-resolved and need compatibility with software that expects the traditional resolvconf interface. Do not include it unless systemd-resolved will be enabled later in this guide.

packages+=(
  systemd-resolvconf # resolvconf compatibility for systemd-resolved
)
NVIDIA open kernel driver

Install this package if your system uses a supported NVIDIA GPU and you want hardware-accelerated graphics. It targets newer GPUs and integrates directly with the Linux kernel.

packages+=(
  nvidia-open        # Open-source NVIDIA kernel driver
)
Btrfs file system utilities

Install these packages if you plan to use Btrfs on the root filesystem or on additional drives.

packages+=(
  btrfs-progs        # Btrfs user-space management tools
  compsize           # Reports compression and disk usage on Btrfs
)

Run package installation

After defining the base system and appending optional packages, run the following command to install all selected packages onto the mounted system.

pacstrap -K /mnt "${packages[@]:?}"

The -K flag ensures a proper pacman keyring setup in the new system.

Prepare the installed system before entering chroot

Fstab (file system table)

Generate the fstab file, which the system uses at boot to determine which filesystems to mount. The -U option ensures partitions are identified by their UUIDs for reliable mounting.

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

Check the generated file to confirm the filesystem entries.

Make any required adjustments to the file based on your setup.

Ext4 generally does not require manual editing. Since genfstab detects active mount options, the flags you used earlier (noatime and commit=30) should already be present.

Edit fstab if changes are needed.

Consider removing any subvolid= entries to rely solely on path-based subvol= mounts. This ensures that your system mounts the correct subvolumes even if their IDs change during a snapshot rollback.

Since genfstab detects active mount options, the flags you used earlier (noatime, flushoncommit, and subvol=) should already be present.

Edit fstab if changes are needed.

Configure systemd-boot

Install the systemd-boot boot manager. This copies the required bootloader files into the EFI System Partition (ESP) and sets up the default configuration directory.

bootctl --esp-path=/mnt/boot install
Run bootctl install again after chrooting

You will need to run bootctl install again once you enter the chroot environment. The live installer may use different package versions than the target system, and reinstalling ensures the bootloader matches the installed system.

The first run must happen outside the chroot because only the live environment can access EFI variables to register the bootloader. This is a known limitation (see systemd issue #36174).

Verify EFI boot entries

By default, bootctl install places the newly created boot entry first in the boot order. If you want to verify it or manage the boot order or other entries, refer to the section below.

Verifying and managing EFI boot entries

Unlike legacy BIOS bootloaders, which reside physically on the disk's Master Boot Record (MBR), UEFI boot entries are stored in the motherboard's NVRAM (Non-Volatile RAM). Because of this, boot entries often persist even after a disk has been formatted or replaced.

Risk of an unbootable system

Deleting or reordering the wrong boot entry can prevent the system from booting. Verify that you are not modifying the entry for your current installation, any other operating systems in a multiboot setup, or the firmware interface.

About the Unicode Switch

Although the UEFI specification mandates UCS-2 (Unicode) encoding for boot entry descriptions and arguments, efibootmgr defaults to ASCII to maintain compatibility with older or non-standard firmware.

Most modern systems follow the standard and require the --unicode switch. However, some firmware implementations are non-compliant and may expect ASCII. If your boot entries appear as unreadable garbage text or fail to pass arguments to the kernel, try toggling this switch to match your firmware's behavior.

View boot order and entries

List your current boot configuration, including the active BootOrder and all available boot entries.

Identify your new entry

Boot lists often contain outdated or default firmware entries, which can make it difficult to find the one you just created. Filter the output by your EFI partition's UUID to locate your new installation.

efibootmgr --unicode | grep -F "$(lsblk --nodeps --noheadings --output PARTUUID "${efi:?}")"

Remove stale entries

Remove leftover entries from earlier installations or tests to keep the boot menu clean.

Replace XXXX with the hexadecimal boot number of the entry you want to remove.

efibootmgr --unicode --delete-bootnum --bootnum XXXX

Modify boot order

If the entries are not arranged as desired, set the full boot order manually.

Copy the boot numbers from the BootOrder line in the previous output. Rearrange them so your preferred entries come first, then apply the updated order.

  • Replace XXX1,XXX2,XXX3 with the actual hexadecimal boot numbers, such as 0001,0002,000A.
  • Always provide the complete list when updating the order, since partial updates are not supported.
  • Any boot entries omitted from the order will not have a chance to boot.
efibootmgr --unicode --bootorder XXX1,XXX2,XXX3

View boot order and entries

List your current boot configuration, including the active BootOrder and all available boot entries.

Identify your new entry

Boot lists often contain outdated or default firmware entries, which can make it difficult to find the one you just created. Filter the output by your EFI partition's UUID to locate your new installation.

efibootmgr | grep -F "$(lsblk --nodeps --noheadings --output PARTUUID "${efi:?}")"

Remove stale entries

Remove leftover entries from earlier installations or tests to keep the boot menu clean.

Replace XXXX with the hexadecimal boot number of the entry you want to remove.

efibootmgr --delete-bootnum --bootnum XXXX

Modify boot order

If the entries are not arranged as desired, set the full boot order manually.

Copy the boot numbers from the BootOrder line in the previous output. Rearrange them so your preferred entries come first, then apply the updated order.

  • Replace XXX1,XXX2,XXX3 with the actual hexadecimal boot numbers, such as 0001,0002,000A.
  • Always provide the complete list when updating the order, since partial updates are not supported.
  • Any boot entries omitted from the order will not have a chance to boot.
efibootmgr --bootorder XXX1,XXX2,XXX3

Configure loader.conf

Set arch.conf as the default boot entry in the global bootloader configuration file.

echo "default arch.conf" >> /mnt/boot/loader/loader.conf

Create arch.conf boot entry

Define the boot process for the Arch Linux kernel.

Get UUID

First, retrieve the UUID of the physical root partition.

root_device_uuid="$(lsblk --nodeps --noheadings --output "UUID" "${root_physical:?}")"
Define kernel arguments

Selecting the right kernel parameters ensures that your system can locate and mount the root filesystem during boot. The next step tailors these parameters to your encryption method.

Include the decryption device (rd.luks.name) and set the root filesystem to the decrypted path (/dev/mapper/luks-root).

kernel_args="rd.luks.name=${root_device_uuid}=luks-root root=/dev/mapper/luks-root"

Set the root filesystem to the UUID of the physical root partition.

kernel_args="root=UUID=${root_device_uuid}"

Before creating the final boot entry, make sure the kernel arguments also match your filesystem type. Some filesystems require extra flags so the kernel knows exactly where your root data is stored.

No additional flags are required because Ext4 uses a straightforward layout that does not involve subvolumes or special mount instructions.

If you used the Btrfs subvolume setup, append the flag specifying the root subvolume.

kernel_args="${kernel_args:?} rootflags=subvol=/@"
Create the configuration file

The microcode files (intel-ucode.img and amd-ucode.img) must appear before the main initramfs-linux.img in the configuration file to ensure they load first. The command below uses tee to create the arch.conf loader entry that references the appropriate microcode file or files, depending on the CPU architecture you select.

Make sure the required microcode files were copied to /mnt/boot. They are installed by pacstrap during the Install essential packages step, where you select your CPU architecture from the corresponding tab.

In this step, you again choose one of the architecture tabs. Select the same architecture as before so that the correct microcode images installed earlier are used in your boot loader configuration.

tee /mnt/boot/loader/entries/arch.conf <<EOF
title   Arch Linux
linux   /vmlinuz-linux
initrd  /intel-ucode.img
initrd  /amd-ucode.img
initrd  /initramfs-linux.img
options ${kernel_args:?} rw
EOF
tee /mnt/boot/loader/entries/arch.conf <<EOF
title   Arch Linux
linux   /vmlinuz-linux
initrd  /intel-ucode.img
initrd  /initramfs-linux.img
options ${kernel_args:?} rw
EOF
tee /mnt/boot/loader/entries/arch.conf <<EOF
title   Arch Linux
linux   /vmlinuz-linux
initrd  /amd-ucode.img
initrd  /initramfs-linux.img
options ${kernel_args:?} rw
EOF

Configure systemd-resolved

The /etc/resolv.conf file is bind-mounted from the host system when using arch-chroot, so it cannot be replaced from inside the chroot. To ensure DNS resolution works correctly on the installed system, you must create the symlink before entering the chroot environment.

Run the following command from outside the chroot.

ln -sf ../run/systemd/resolve/stub-resolv.conf /mnt/etc/resolv.conf

Info

For more details about DNS handling and alternative setups, see the systemd-resolved wiki page.

Copy iwd configuration (optional)

If you successfully connected to Wi-Fi in the live environment and plan to manage wireless networks with iwd, you can copy the iwd wireless network configuration files to the installed system. This allows the same Wi-Fi setup to be available after reboot, so you do not need to configure it again.

First, create the iwd configuration directory.

mkdir -m 700 /mnt/var/lib/iwd

Next, copy the network configuration files. It is safe to ignore any omitting directory warnings, as directories do not need to be copied.

cp /var/lib/iwd/* /mnt/var/lib/iwd

Chroot into the installed system for final configuration

Change the root directory to the newly installed system to complete the final configuration steps.

In an Arch Linux installation, chroot (change root) places you inside the installed system environment. Until now, you have been working from the live installation environment, which is outside the installed system. After chrooting, all commands will run as if the system were already booted.

Time configuration

Configure the system clock to use the correct time zone and keep it synchronized automatically.

First, list all supported time zones and identify the one that matches your region or intended system role, such as UTC for servers.

timedatectl list-timezones | more

Then, set the system time zone by linking /etc/localtime to the appropriate zoneinfo file. Replace Etc/UTC with the time zone you want.

ln -sf /usr/share/zoneinfo/Etc/UTC /etc/localtime

Next, synchronize the hardware clock with the current system time and generate /etc/adjtime.

Finally, enable automatic network time synchronization to keep the clock accurate.

systemctl enable systemd-timesyncd.service

Localization

This section configures the system language, regional formatting, and console behavior.

Configure /etc/locale.gen

Locales must be generated before they can be used. The file /etc/locale.gen determines which locales will be built by locale-gen.

You can either edit the file and uncomment the locales you need, or overwrite it with only the required entries. Both methods are valid.

Begin by creating a backup of the file for future reference.

cp /etc/locale.gen /etc/locale.gen-dist

Next, list the available locales. The example below filters for English locales, but you can adjust the search pattern.

grep -i en /usr/share/i18n/SUPPORTED

Finally, write your selected locales to /etc/locale.gen. The example demonstrates a mixed European style that will be described later.

cat <<EOF > /etc/locale.gen
en_DK.UTF-8 UTF-8
en_IE.UTF-8 UTF-8
en_US.UTF-8 UTF-8
EOF

Open /etc/locale.gen and remove the leading # from the locales you want to enable.

After updating the file, generate the locales:

Create /etc/locale.conf

Create /etc/locale.conf to define system-wide locale environment variables.

The example below uses English (United States) for system messages, which is the least surprising option for most Linux software, while applying ISO date and time formatting, metric units for measurements, the euro for currency, and ISO 216 A4 as the default paper size.

cat <<EOF > /etc/locale.conf
LANG=en_US.UTF-8
LC_MEASUREMENT=en_IE.UTF-8
LC_MONETARY=en_IE.UTF-8
LC_PAPER=en_IE.UTF-8
LC_TIME=en_DK.UTF-8
EOF

Configure the virtual console

The virtual console settings control the keyboard layout and font used in TTYs and during early boot.

Edit /etc/vconsole.conf to set KEYMAP and FONT.

Example configuration for a US keyboard layout with the Terminus font (Western European codepage, 28 pixel height, bold):

cat <<EOF > /etc/vconsole.conf
KEYMAP=us
FONT=ter-124b
EOF

Ensure correct keymap for disk unlock

When using LUKS full disk encryption, the KEYMAP defined in /etc/vconsole.conf is the only keyboard layout available during boot when entering the unlock password. This layout must match your physical keyboard exactly, or you may not be able to type the correct password.

Network configuration

Set a unique hostname for your system.

echo myhostname > /etc/hostname

Configure systemd-resolved to use DNS over TLS

Enable the systemd-resolved service.

systemctl enable systemd-resolved.service

Create the configuration drop-in directory.

mkdir -p /etc/systemd/resolved.conf.d

Create a drop-in configuration file for your preferred DNS provider. Use one of the examples below or provide your own configuration. These examples enforce encrypted DNS resolution for all domains.

cat <<EOF > /etc/systemd/resolved.conf.d/dns_over_tls.conf
[Resolve]
DNS=1.1.1.1#cloudflare-dns.com 1.0.0.1#cloudflare-dns.com 2606:4700:4700::1111#cloudflare-dns.com 2606:4700:4700::1001#cloudflare-dns.com
DNSOverTLS=yes
Domains=~.
EOF
cat <<EOF > /etc/systemd/resolved.conf.d/dns_over_tls.conf
[Resolve]
DNS=8.8.8.8#dns.google 8.8.4.4#dns.google 2001:4860:4860::8888#dns.google 2001:4860:4860::8844#dns.google
DNSOverTLS=yes
Domains=~.
EOF
cat <<EOF > /etc/systemd/resolved.conf.d/dns_over_tls.conf
[Resolve]
DNS=1.1.1.1#cloudflare-dns.com 1.0.0.1#cloudflare-dns.com 2606:4700:4700::1111#cloudflare-dns.com 2606:4700:4700::1001#cloudflare-dns.com 8.8.8.8#dns.google 8.8.4.4#dns.google 2001:4860:4860::8888#dns.google 2001:4860:4860::8844#dns.google
DNSOverTLS=yes
Domains=~.
EOF

Network management

If you installed GNOME with NetworkManager, networking is handled automatically. NetworkManager will be enabled in a later section.

If you did not install GNOME or NetworkManager, you need to configure networking manually. The example below uses systemd-networkd and works out of the box for a wired Ethernet connection using DHCP. Optional Wi-Fi support is included via iwd.

Configure networking with systemd-networkd and iwd

Enable the systemd-networkd service so it can manage network interfaces at boot.

systemctl enable systemd-networkd.service

Create a basic DHCP profile for wired Ethernet interfaces.

cat <<EOF > /etc/systemd/network/10-wired.network
[Match]
Name=en*
Name=eth*

[Link]
RequiredForOnline=routable

[Network]
DHCP=yes

[DHCPv4]
RouteMetric=100

[IPv6AcceptRA]
RouteMetric=100
EOF

If you use Wi-Fi, enable the iwd service so it can manage wireless networking.

systemctl enable iwd.service

Create a wireless network profile. After rebooting, you can use iwctl or the more user-friendly impala tool to manage wireless connections.

cat <<EOF > /etc/systemd/network/60-wireless.network
[Match]
Name=wl*

[Link]
RequiredForOnline=routable

[Network]
DHCP=yes

[DHCPv4]
RouteMetric=600

[IPv6AcceptRA]
RouteMetric=600
EOF

Enable services that you may have optionally installed

GNOME desktop environment

If you installed the GNOME desktop environment, you need to enable a few services to ensure a fully functional graphical system.

Enable the GNOME display manager so the graphical login screen starts automatically at boot.

systemctl enable gdm.service

Enable NetworkManager so network connections are managed automatically.

systemctl enable NetworkManager.service

Enable the Bluetooth service to manage Bluetooth devices.

systemctl enable bluetooth.service

Info

See the GDM guide for details on the GNOME display manager, the NetworkManager guide for configuring networking, and the Bluetooth page for setting up Bluetooth support.

Set root password and create a user

Set a password for the root account. Even if you normally use sudo for administrative tasks, the root password is required for system recovery tasks such as entering the systemd emergency shell.

Choose a username for your regular account (example: foo).

Create the user, including a home directory, and add them to the wheel group to allow administrative access via sudo.

useradd --create-home --groups wheel "${username:?}"

Set a password for the new user.

Enable sudo access for members of the wheel group.

echo "%wheel ALL=(ALL:ALL) ALL" > /etc/sudoers.d/allow-wheel

Swap space setup

Even on systems with plenty of RAM, swap plays an important role. It provides backing storage for inactive memory pages, helping the kernel manage physical RAM more efficiently.

Choose the method that matches your filesystem to create and enable a swap file. The examples below use an 8 GiB swap file, but the same steps apply to other sizes.

Create a swap file on an Ext4 root filesystem and ensure it is activated at boot.

Start by creating a directory to hold the swap file.

Create the swap file with a fixed UUID and the desired size.

mkswap --uuid clear --size 8G --file /swap/swapfile

Add the swap file to fstab so it is enabled automatically during boot.

echo "/swap/swapfile none swap defaults 0 0" >> /etc/fstab

Info

For more background and tuning options, see the Swap documentation.

Create a swap file using Btrfs-specific tooling and enable it at boot. In this example, /swap refers to a directory where a dedicated @swap subvolume is already mounted.

Use the Btrfs helper command to create the swap file.

btrfs filesystem mkswapfile --size 8g --uuid clear /swap/swapfile

Register the swap file in fstab so it is activated automatically.

echo "/swap/swapfile none swap defaults 0 0" >> /etc/fstab

Enable periodic TRIM

If your root filesystem is ext4 on an SSD, enable the fstrim timer so the system periodically issues TRIM to free unused blocks. This helps maintain SSD write performance over time.

systemctl enable fstrim.timer

No action is needed, since Btrfs automatically enables the discard=async mount option on devices that support it.

Configure mkinitcpio

The initial ramdisk environment (initramfs) must be configured correctly to ensure successful system booting, particularly when using LUKS encryption or proprietary NVIDIA drivers.

You can add drop-in configuration files or make the changes manually. If you choose manual configuration, open the primary configuration file and follow the instructions below.

nano /etc/mkinitcpio.conf

Configure boot-time initramfs settings

Configure disk encryption

Integrate the sd-encrypt hook into the HOOKS array. This hook enables the system to prompt for decryption during the early boot stage.

Create the following drop-in configuration file to automatically insert sd-encrypt immediately after the block hook in the HOOKS= array.

cat <<'EOF' > /etc/mkinitcpio.conf.d/10-add-luks-encryption-hook.conf
mapfile -t HOOKS < <(
  for element in "${HOOKS[@]}"; do
    echo "$element"
    if [ "$element" = "block" ]; then
      echo "sd-encrypt"
    fi
  done
)
EOF

Locate the HOOKS= line and manually insert sd-encrypt after the block hook and before the filesystems hook.

HOOKS=(... block sd-encrypt filesystems ...)

No changes are required.

Configure the NVIDIA driver

To ensure the proprietary NVIDIA driver initializes correctly during the early boot stage, update both the HOOKS and MODULES arrays.

Remove the kms hook from HOOKS

Removing kms from the HOOKS array prevents the inclusion of the nouveau module in the initramfs, ensuring the kernel cannot load the open-source driver early in the boot process and avoiding conflicts with the proprietary NVIDIA driver.

Add this drop-in configuration file that will remove kms from HOOKS array

cat <<'EOF' > /etc/mkinitcpio.conf.d/20-remove-kms-hook.conf
mapfile -t HOOKS < <(
  for element in "${HOOKS[@]}"; do
    if [ "$element" != "kms" ]; then
      echo "$element"
    fi
  done
)
EOF

If kms appears in your HOOKS array, remove it.

HOOKS=(...) # Make sure "kms" is not included!
Add the required NVIDIA modules to MODULES

These kernel modules ensure the NVIDIA driver stack is available early in the boot process.

Choose the configuration that matches your system.

This configuration is for systems that use only an NVIDIA GPU.

The proprietary NVIDIA driver requires the following kernel modules to be loaded during early boot.

Create a drop-in configuration file that appends the required NVIDIA kernel modules to the mkinitcpio MODULES array.

cat <<EOF > /etc/mkinitcpio.conf.d/30-add-nvidia-modules.conf
MODULES+=(nvidia nvidia_modeset nvidia_uvm nvidia_drm)
EOF

Add the following NVIDIA kernel modules to the MODULES array.

MODULES=(nvidia nvidia_modeset nvidia_uvm nvidia_drm)

This configuration is for systems with an NVIDIA GPU and an Intel integrated GPU (Optimus or hybrid graphics).

Early boot requires both the Intel i915 module and the NVIDIA driver modules.

Create a drop-in configuration file that appends the required Intel and NVIDIA kernel modules to the mkinitcpio MODULES array.

cat <<EOF > /etc/mkinitcpio.conf.d/30-add-nvidia-modules.conf
MODULES+=(i915 nvidia nvidia_modeset nvidia_uvm nvidia_drm)
EOF

Add the following Intel and NVIDIA kernel modules to the MODULES array.

MODULES=(i915 nvidia nvidia_modeset nvidia_uvm nvidia_drm)

Regenerate initramfs

Save your changes if you edited the configuration file manually, then regenerate all initramfs images.

Boot loader finalization

Re-run the boot installation command inside the chroot to ensure the bootloader files on the ESP match the system's installed version.

Enable the automatic update service for systemd-boot to ensure the bootloader files are updated whenever the systemd package is upgraded.

systemctl enable systemd-boot-update.service

Install AUR helper (optional)

Install yay, a popular helper for installing and managing packages from the Arch User Repository (AUR).

Installation steps

Use the prebuilt yay-bin package from the AUR. This avoids compiling yay from source while still following the standard AUR workflow.

Switch to the regular user account created earlier. You may see the error message tty: ttyname error: No such device. This happens because the chroot environment cannot resolve the terminal device path from the host. It is safe to ignore and does not affect the user session.

runuser -l "${username:?}"

Now, acting as your regular user, create a temporary directory and switch to it. This directory will be used to build the package.

Clone the yay-bin AUR repository into the current directory.

git clone https://aur.archlinux.org/yay-bin.git .

Build and install the package.

Configure yay to always check for updates to development (-git) packages.

Exit the user shell to return to the root environment.

Info

See the AUR helpers guide and the yay project for more information.

Exit chroot and reboot

Exit the chroot environment to return to the live installation shell.

Ensure the installation USB drive has been removed, then reboot the system into your new Arch Linux installation.

Post-installation

Congratulations! Your Arch Linux system is now ready to use.

To keep your system and AUR packages up to date, you can use yay (if installed). It acts as a wrapper for pacman and handles official and community updates simultaneously.

Alternatively, you can use the default package manager, pacman, for official repository updates.