Arch Linux

Install Arch Linux with archinstall: Step-by-Step Guide

A GNOME desktop on Btrfs with systemd-boot, zram swap and a firewall took 7 minutes and 2 seconds on the test box, measured by archinstall itself from the install confirmation to the “Installation completed” screen, and mirror ranking alone consumed about two of those minutes. The guided installer on the current Arch ISO ships unified kernel images by default, a firewall picker, Snapper and Timeshift integration, a split firmware menu, and an encrypted credentials file for unattended installs.

Original content from computingforgeeks.com - post 116424

This archinstall guide walks every menu in the order the installer presents it, with the choice that was made on the test box and the reason for it. It then repeats the same Arch Linux install from a saved config file with --silent, which is where one real bug surfaced: a Snapper selection stored in the config file is silently ignored. The workaround is included and was verified on the installed system. For a fully manual Arch Linux install guide with LVM, the manual LVM on UEFI walkthrough covers the pacstrap route.

Tested October 2026 on archinstall 4.5 (Arch ISO 2026.10.01).

What the current archinstall menus default to

Several defaults differ from what older archinstall guides describe, including the earlier version of this one, which recommended GRUB. The table lists what the current ISO presents, taken from the screens captured during the test runs.

AreaCurrent ISOPractical effect
Default bootloadersystemd-boot, unified kernel images enabledOne EFI binary per kernel, no loader entry files
Bootloader choicessystemd-boot, GRUB, EFISTUB, Limine, rEFIndGRUB still needed for BIOS or grub-btrfs
Btrfs snapshotsSnapper or Timeshift submenuAppears only when subvolumes are created
Firewallufw or firewalld under ApplicationsInbound traffic denied from first boot
FirmwareSeparate menu for six split firmware packagesNone installed unless picked
base-develNot installedAdd it before planning AUR builds
NVIDIA optionnvidia-open-dkmsTuring and newer GPUs only
Desktop profiles21, including Cosmic, niri and LabwcPackage list previewed per profile
Credentials fileOptional argon2id encryption with a keySafe to store next to the config

Prerequisites

  • A UEFI machine, because the default layout and systemd-boot assume UEFI; legacy BIOS installs need GRUB or Limine.
  • 4 GB of RAM for a GNOME install, since the installed desktop used 1.38 GiB at idle on the test box.
  • At least 20 GB of disk, because the finished GNOME system occupied 4.4 GB on a 32 GB Btrfs volume with zstd compression.
  • A USB stick of 2 GB or larger and a wired connection, or Wi-Fi that iwctl can join.
  • Lab used here: a Proxmox VM (OVMF firmware, 4 vCPU, 4 GB RAM, 32 GB VirtIO SCSI disk) named bench01.

Step 1: Write the Arch ISO to a USB drive

Download the current ISO from the Arch Linux download page. Every mirror also publishes the release under iso/latest/ with the stable name archlinux-x86_64.iso, which keeps the command below valid month to month. Identify the USB device with lsblk first, because dd overwrites whatever device it is given:

sudo dd if=archlinux-x86_64.iso of=/dev/sdX bs=4M status=progress oflag=sync

On Windows, Rufus in DD mode or Ventoy produce a bootable stick from the same file.

Step 2: Boot the live environment and check UEFI and the network

Boot from the stick and wait for the root shell, then confirm the boot mode: a 64-bit UEFI boot exposes the firmware platform size, and the value must read 64 before continuing with the default layout:

cat /sys/firmware/efi/fw_platform_size

If that file does not exist, the machine booted in legacy BIOS mode. Fix the boot order in the firmware setup and boot the stick again. Wired networks come up through DHCP on their own; Wi-Fi needs the wireless device name first, because it is not always wlan0, and then one iwctl call with the SSID of the access point:

iwctl device list
iwctl station wlan0 connect "HomeNetwork"

Confirm that the package mirrors are reachable before starting the installer:

ping -c 3 archlinux.org

Step 3: Launch archinstall

The installer is preinstalled on the ISO and checks for a newer release of itself on start:

archinstall

After “Fetching Arch Linux package database…” the main menu appears. The right pane previews the current value of whichever entry is highlighted, so every setting can be reviewed without opening it. Arrow keys move, Enter opens an entry, Space toggles items in multi-select lists, and / starts a filter.

archinstall main menu on the Arch Linux live ISO

Two keyboard habits avoid most of the mistakes made during the first test run. Many Yes/No prompts open with “Yes” highlighted, so a stray Down arrow lands on “No”. Pressing Enter in a multi-select list with nothing checked selects the highlighted row, which is how an unwanted firmware package was picked up, and Ctrl+c resets the current setting after a confirmation prompt.

Step 4: Set locales, mirrors and optional repositories

Archinstall language only changes the installer interface, not the installed system. Locales holds four values: keyboard layout (us), locale language (en_US.UTF-8), encoding (UTF-8) and console font (default8x16), and all four defaults were kept on the test box.

Mirrors and repositories splits into four submenus that control where packages come from: Select regions, Add custom servers, Optional repositories and Add custom repository. Selecting a single region (Germany for the test box) still pulled 103 mirror URLs into the config, which archinstall then ranks by download speed. That ranking took 1 minute 57 seconds of the unattended run, and several mirrors were skipped with “HTTP Error 403: Forbidden” during the test. The ranked list put a plain HTTP mirror first, which is acceptable because pacman verifies package signatures regardless of transport. Optional repositories offers multilib, multilib-testing, core-testing and extra-testing. Enable multilib for Steam, Wine or any 32-bit library; leave the testing repositories off on a workstation.

Step 5: Configure the disk layout, Btrfs subvolumes and snapshots

Disk configuration wipes the selected drive, so confirm the device name twice. Partitioning offers three modes: “Use a best-effort default partition layout”, “Manual Partitioning” and “Pre-mounted configuration”. The default layout on a 32 GB disk produced a 1 GiB FAT32 /boot (the EFI system partition) and a 31 GiB root partition. The filesystem choices are btrfs, ext4, xfs and f2fs, and only btrfs unlocks the subvolume and snapshot options below.

Choosing btrfs triggers two follow-up prompts, and the first asks whether to create subvolumes with a default structure, and the answer should be Yes. The first test run answered No by accident: the result was a single top-level volume mounted as subvol=/, with no @home and no way to add snapshot support from the menu. The second prompt picks compression or disabled copy-on-write; compression adds compress=zstd to the mount options. With both answered, the layout preview shows the four subvolumes:

archinstall default Btrfs layout with @ @home @log @pkg subvolumes and zstd compression

Separate @log and @pkg subvolumes keep logs and the pacman package cache out of root snapshots, so a rollback does not resurrect old logs or bloat snapshots with cached packages. The installed system mounted all four with compress=zstd:3,ssd,discard=async,space_cache=v2.

Once subvolumes exist, a “Btrfs snapshots” entry appears in the disk submenu with Snapper and Timeshift as choices, and Snapper was selected for the test:

archinstall Btrfs snapshots submenu with Snapper selected

The same submenu holds LVM (it creates a volume group named ArchinstallVg) and Disk encryption, which offers LUKS only. Encryption prompts for a passphrase at every boot, so it suits laptops more than headless boxes. The LUKS encryption install guide covers the manual equivalent with more control over the cipher and key slots.

Step 6: Choose swap, bootloader, kernels and firmware

Swap is zram only, with no swap partition or swap file option. The algorithm list offers zstd, lzo-rle, lzo, lz4 and lz4hc; zstd was kept. On the 4 GB test box this produced a 1.9 GiB /dev/zram0 at priority 100, and archinstall added zswap.enabled=0 to the kernel command line so the two compressed-swap mechanisms do not stack.

The bootloader list now has five entries, and systemd-boot is the default and the right choice for a UEFI machine; GRUB remains the option for BIOS systems or for grub-btrfs snapshot boot entries.

archinstall bootloader list with systemd-boot, GRUB, EFISTUB, Limine and rEFInd

Unified kernel images are enabled by default, which means the kernel, initramfs and command line are bundled into one EFI binary at /boot/EFI/Linux/arch-linux.efi, and systemd-boot discovers it without a loader entry file. The Plymouth submenu asks before enabling a boot splash and lists the two known failure cases:

archinstall Plymouth prompt warning about NVIDIA black screen and hidden LUKS prompt

Plymouth was left disabled on the test box. The kernel list covers linux, linux-hardened, linux-lts, linux-rt, linux-rt-lts and linux-zen. Installing linux-lts next to linux gives a second UKI to boot when a mainline update misbehaves, at the cost of one more image on /boot (the test UKI measured 30.5 MB).

Additional firmware is a new menu that exists because Arch split several vendor blobs out of linux-firmware, and the menu title states plainly that “none are pulled in by linux-firmware”:

archinstall additional firmware menu listing linux-firmware split packages

Desktops and laptops rarely need any of these packages, while Mellanox Spectrum switches, QLogic and Marvell adapters, Netronome flow processors and Qualcomm SoC devices usually do. Nothing was selected on the test box.

Step 7: Set the hostname and create a sudo user

Hostname defaults to archlinux, and the test box used bench01 to match its role. Authentication holds three entries: Root password, User account and U2F login setup. The U2F entry reported “No U2F devices found” on the VM. Inside User account, add a user, set a password, and answer Yes to the superuser question:

archinstall user account creation with superuser sudo prompt

An existing user can be promoted later from the user list through “Promote/Demote user”. With the root password left unset, the installed system shipped root locked (passwd -S root reported L), and archinstall wrote /etc/sudoers.d/00_klinsmann containing klinsmann ALL=(ALL) ALL. A locked root with one sudo user is a sensible default for a desktop.

Step 8: Pick the desktop profile, graphics driver and greeter

Profile types are Desktop, Minimal, Server and Xorg, and the Desktop list now carries 21 environments and window managers, and the right pane shows exactly which packages each one installs. GNOME pulls in gnome and gnome-tweaks:

archinstall desktop profile list with GNOME selected

The Desktop profile type also installs a small common set: htop, nano, openssh, smartmontools, vim, wget and xdg-utils. In the graphics driver menu that follows, the NVIDIA entry installs the open kernel module through DKMS, which supports Turing (GTX 16xx and RTX 20xx) and newer cards only:

archinstall graphics driver menu showing nvidia-open-dkms for Turing and newer GPUs

Maxwell, Pascal and Volta cards are no longer covered by the official repositories; those need nvidia-580xx-dkms from the AUR after first boot (Kepler and older need the 470xx branch), which the Arch Linux post-install guide covers in its GPU section. “All open-source” installs Mesa plus the AMD, Intel and nouveau user-space drivers and is the safe choice for a VM or mixed hardware; it was used on the test box. The greeter list offers gdm, sddm, lightdm-gtk-greeter, lightdm-slick-greeter, ly, cosmic-greeter, dms-greeter and plasma-login-manager. GDM is preselected when the GNOME profile is chosen.

Step 9: Select applications, networking and extra packages

Applications covers Bluetooth, Audio, Print service, Firewall and Additional fonts. PipeWire was selected for audio, and the font list offered noto-fonts, noto-fonts-emoji, noto-fonts-cjk, ttf-liberation and ttf-dejavu (the first two were picked). The firewall choice is new and has two options:

archinstall firewall choice between ufw and firewalld

Choosing ufw installs it, enables ufw.service and activates a default deny-incoming policy. That policy matters for anyone who adds sshd later: the service starts, but connections time out until port 22 is allowed. The troubleshooting entry near the end shows the exact symptom.

Network configuration lists five backends and prints its own recommendation at the top:

archinstall network configuration options including NetworkManager and iwd

“Use Network Manager (default backend)” was selected because GNOME manages Wi-Fi and VPNs through NetworkManager. “Copy ISO network configuration to installation” is the highlighted default, and it suits a server that should keep the systemd-networkd setup the live ISO negotiated. The Pacman entry exposes only the Color toggle, although the saved config also carries parallel_downloads: 5.

Additional packages opens a searchable picker over the full repository and prints a warning that is easy to miss: “Note: base-devel is no longer installed by default. Add it here if you need build tools.” Without base-devel, makepkg fails on the first AUR build, so add it along with git if an AUR helper is planned. The test box added base-devel, fastfetch and git through the filter. Timezone was set to Europe/Berlin through the filter, and automatic time sync (NTP) stayed enabled.

Step 10: Save the configuration and start the install

Save configuration writes the choices to disk before anything is installed. It offers “Save user configuration (including disk layout)”, “Save user credentials” and “Save all”, then asks for a directory and whether to encrypt user_credentials.json. Choosing encryption prompts for a key and stores the user password hashes as an argon2id-protected blob. Save all, encrypt the credentials, and copy both files somewhere off the live ISO; Step 12 replays them.

Install shows the full JSON that is about to be applied. The prompt defaults to No, so an accidental Enter aborts instead of wiping the disk:

archinstall install confirmation prompt with JSON configuration preview

After Yes, a five second countdown precedes the disk wipe, and the installer then waits for time sync and for archlinux-keyring-wkd-sync, ranks mirrors, pacstraps the base system, installs the bootloader, profile and services, and generates fstab. The interactive run ended on this menu:

archinstall installation completed screen with reboot and chroot options

The chroot option opens a shell inside /mnt for last-minute changes, such as editing /etc/kernel/cmdline or adding a second user; otherwise choose Reboot system and remove the USB stick.

Step 11: First boot into the new Arch Linux system

The boot captures and measurements below come from the third test run (the silent install with Snapper, described in Step 12), which used the same menu choices as the interactive session plus working subvolumes. The loader timeout is 3 seconds, so the systemd-boot menu flashes past; pressing an arrow key during the countdown stops it. It lists one entry for the UKI plus the firmware setup shortcut; the default preset builds no fallback image:

systemd-boot menu with the Arch Linux unified kernel image entry

The UKI shows the Arch splash bitmap while systemd starts, and graphical.target was reached 5.7 seconds after the kernel started:

GDM login screen on Arch Linux installed with archinstall

GNOME opens the welcome tour on the first login, and Skip closes it for good:

GNOME welcome tour on first login to Arch Linux

GNOME Console is the default terminal (search for “Console”, not “Terminal”). fastfetch, added under Additional packages, summarises the result:

fastfetch output in GNOME Console on Arch Linux installed with archinstall

The boot time breakdown for the first boot comes from systemd-analyze:

systemd-analyze

Userspace dominated, and ldconfig.service (1.196 s) was the slowest unit on the first boot only:

Startup finished in 1.852s (kernel) + 3.836s (userspace) = 5.688s
graphical.target reached after 3.835s in userspace.

Check that no unit failed, that zram is active and how much space the install used:

systemctl --failed --no-legend; zramctl; df -h / /boot

No failed units were listed, zram reported its 1.9 GiB device, and the GNOME install used 4.4 GB of the root volume:

NAME       ALGORITHM DISKSIZE DATA COMPR TOTAL STREAMS MOUNTPOINT
/dev/zram0 zstd          1.9G   4K   64B   20K         [SWAP]
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda2        31G  4.4G   27G  15% /
/dev/sda1      1022M   46M  977M   5% /boot

From here, the things to do after installing Arch Linux cover mirrors, microcode, codecs and hardening. Package management day to day is in the pacman cheat sheet.

Step 12: Repeat the install unattended from an archinstall config file

The two files saved in Step 10 turn the whole menu session into one command. The flags that matter are --config and --creds (each also has a -url variant for files served over HTTP), --creds-decryption-key, --silent and --dry-run. With the files copied to /root/cfg on a fresh live ISO, start the unattended install:

archinstall --config /root/cfg/user_configuration.json --creds /root/cfg/user_credentials.json --silent

Passing --creds-decryption-key on the command line works, but it leaves the key in shell history. Omitting it makes archinstall prompt for the key even in silent mode, which is the better habit. A wrong key is rejected before the disk is touched:

archinstall silent mode credentials decryption prompt showing Incorrect password

Adding --dry-run to the same command parses the files, checks the bootloader against the disk layout, prints “Fetching Arch Linux package database…” and exits. The disk on the test box was unchanged afterwards. It catches broken JSON and a wrong key, but misspelled keys are ignored silently, so compare an edited file with diff against the saved one as shown below. The silent run printed the same progress as the interactive one and finished with:

Activating systemd-timesyncd for time synchronization using Arch Linux and ntp.org NTP servers
Enabling service systemd-timesyncd
Updating /mnt/etc/fstab
Syncing the system...
Installation completed without any errors.
Log files temporarily available at /var/log/archinstall.
You may reboot when ready.

The saved config is plain JSON, so jq reads the decisions back. The archinstall documentation describes every key:

jq -c '{version, bootloader_config, network_config, swap, snapshot: .disk_config.btrfs_options.snapshot_config, subvolumes: [.disk_config.device_modifications[0].partitions[1].btrfs[].name]}' user_configuration.json | jq .

The file from the test run records systemd-boot with UKI, NetworkManager, zstd zram, Snapper and the four subvolumes:

{
  "version": "4.5",
  "bootloader_config": {
    "bootloader": "Systemd-boot",
    "removable": false,
    "uki": true
  },
  "network_config": {
    "type": "nm"
  },
  "swap": {
    "algorithm": "zstd",
    "enabled": true
  },
  "snapshot": {
    "type": "Snapper"
  },
  "subvolumes": [
    "@",
    "@home",
    "@log",
    "@pkg"
  ]
}

Snapper selected in the config file, but not installed

The silent install from that file completed without errors, mounted all four subvolumes, and installed no Snapper at all: no snapper package, no /etc/snapper/configs, no timers. The cause is in the config loader, where subvolume names read from JSON are stored as strings, while the check that detects the default @ layout compares the name against a Path('@') object. The comparison is always false, so archinstall concludes the layout is not the default one, never parses btrfs_options, and skips the Snapper setup step. The same check exists on the upstream master branch at the time of testing. Going by the source, the interactive menu builds those objects as paths, so a Snapper choice made in the menus does not pass through this loader path; the test runs here covered the config-file path only.

The workaround uses custom_commands, which archinstall runs inside the target chroot after the profile and services are installed. Edit the saved file on the live ISO:

vim /root/cfg/user_configuration.json

Replace the empty custom_commands list and append snap-pac and snapper to packages. The diff between the saved file and the one used for the third test run shows the only two changes:

23c23,27
<     "custom_commands": [],
---
>     "custom_commands": [
>         "snapper --no-dbus -c root create-config /",
>         "snapper --no-dbus -c home create-config /home",
>         "systemctl enable snapper-timeline.timer snapper-cleanup.timer"
>     ],
248c252,254
<         "git"
---
>         "git",
>         "snap-pac",
>         "snapper"

These are the same three steps the Snapper routine inside archinstall performs. --no-dbus is required because the chroot has no running D-Bus. Running snapper list-configs through arch-chroot without the flag printed Failure (org.freedesktop.DBus.Error.ServiceUnknown) on the test box. The install log confirmed the commands ran:

[2026-10-02 13:47:22] - INFO - Installing packages: ['base-devel', 'fastfetch', 'git', 'snap-pac', 'snapper']
[2026-10-02 13:47:38] - INFO - Executing custom command "snapper --no-dbus -c root create-config /" ...
[2026-10-02 13:47:38] - INFO - Executing custom command "snapper --no-dbus -c home create-config /home" ...
[2026-10-02 13:47:38] - INFO - Executing custom command "systemctl enable snapper-timeline.timer snapper-cleanup.timer" ...
[2026-10-02 13:47:38] - INFO - Installation completed without any errors.

On the booted system, snap-pac wraps every pacman transaction in a pre and post snapshot. Install any package with pacman and then list the snapshots of the root config:

sudo pacman -S --noconfirm htop
sudo pacman -S --noconfirm tree
sudo snapper -c root list

Each of the two transactions produced a numbered pair (htop was already present, so pacman reinstalled it), with the pacman command line as the description:

# | Type   | Pre # | Date                     | User | Cleanup | Description                | Userdata
--+--------+-------+--------------------------+------+---------+----------------------------+---------
0 | single |       |                          | root |         | current                    |
1 | pre    |       | Fri Oct  2 19:35:16 2026 | root | number  | pacman -S --noconfirm htop |
2 | post   |     1 | Fri Oct  2 19:35:17 2026 | root | number  | htop                       |
3 | pre    |       | Fri Oct  2 19:35:19 2026 | root | number  | pacman -S --noconfirm tree |
4 | post   |     3 | Fri Oct  2 19:35:19 2026 | root | number  | tree                       |

snapper places .snapshots as a nested subvolume inside @ rather than as a separate top-level @snapshots. Snapshot creation and the timeline and cleanup timers work with that layout, as the listing above shows. A full root rollback by booting a snapshot needs the flat layout described in the Arch Wiki Snapper page, or GRUB with grub-btrfs.

Error: “ssh: connect to host 10.0.1.50 port 22: Connection timed out” after installing

This is the ufw default policy, not a broken sshd: with the firewall chosen in Step 9 and sshd enabled later, the service listens but ufw drops the packets, so the client times out instead of getting “Connection refused”. Linux clients print “Connection timed out”; the macOS client used against the test box printed this:

ssh: connect to host 10.0.1.50 port 22: Operation timed out

Allow SSH from a local terminal on the machine and check the active rules:

sudo ufw allow ssh
sudo ufw status verbose

The rule set now admits port 22 over IPv4 and IPv6, and the default stays deny for everything else:

Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
22                         ALLOW IN    Anywhere
22 (v6)                    ALLOW IN    Anywhere (v6)

Install timings measured on the test box

Three installs ran on the same VM against the same mirror region. Run 1 was the interactive session (without subvolumes, because of the mistaken No). Run 2 replayed the saved config silently, and run 3 replayed the edited config with the Snapper workaround.

RunMethodWall timePackagesRoot usedSnapper
1Interactive menus7m 2s8114.2 GBNo (no subvolumes)
2--config --creds --silent7m 46s8114.2 GBNo (loader bug)
3Silent plus custom_commands6m 35s8134.4 GBYes, root and home

Run 1 is the timer built into archinstall, which starts at the install confirmation. Runs 2 and 3 were timed with the shell time builtin, so they also include the package database fetch, typing the decryption key and the five second countdown. The install log from run 3 breaks the work down by phase, with shares taken over the 6m 16s between the disk wipe and the final log line:

Phase (run 3)DurationShare
Partition and format, start installation3 s1%
Mirror ranking1m 57s31%
Base pacstrap (base, linux, linux-firmware, mkinitcpio, btrfs-progs, sudo)1m 20s21%
zram, bootloader, NetworkManager, PipeWire, ufw, fonts, drivers1m 13s19%
GNOME profile and GDM1m 27s23%
Extra packages, custom commands, fstab16 s4%

The number that matters is the mirror ranking share: almost a third of the install went to timing mirrors, not to downloading packages. Choosing one or two nearby mirrors under “Add custom servers” instead of a whole region removes most of that wait on repeat installs. Once the desktop is up, an AUR helper is usually the next step; the yay install guide needs the base-devel and git packages added in Step 9, and the yay vs pacman vs paru comparison helps decide between the two helpers.

Keep reading

Install KVM and Virt-Manager on Arch Linux Virtualization Install KVM and Virt-Manager on Arch Linux Backup and Restore Linux Systems with Timeshift Debian Backup and Restore Linux Systems with Timeshift Things to Do After Installing CachyOS Arch Linux Things to Do After Installing CachyOS Install COSMIC Desktop on Fedora: Spin, Atomic or dnf group Desktop Install COSMIC Desktop on Fedora: Spin, Atomic or dnf group Install RustDesk on Ubuntu 26.04/24.04 with a Self-Hosted Server Desktop Install RustDesk on Ubuntu 26.04/24.04 with a Self-Hosted Server How to Install MX Linux (Step-by-Step with Screenshots) Desktop How to Install MX Linux (Step-by-Step with Screenshots)

Leave a Comment

Press ESC to close