I have installed Arch several times in my life and have gotten pretty used to the process. But one issue that has been bugging me recently was that I always needed to connect a keyboard and monitor to the box I’m installing to. This meant temporarily dragging my servers close to my desk, which is a bit of a pain.

This time I decided to actually try and do a full headless setup, relying on SSH. Note that this still involves preparing a live USB, so this only applies to machines you have physical access to.

The resources I found useful were:

Caveat

This process is not bulletproof: the main issue is that you need to make sure that your server will always boot into live USB when it’s inserted. This is necessary to start the installation and also to recover any failed state you may run into.

In my case, my server had a rEFind bootloader already installed and configured as the UEFI boot executable. So I could guarantee the boot order within rEFInd by setting in my refind.conf:

scanfor external,internal

Prerequisites

  • Server that you are installing to needs to be connected to a wired LAN.
  • Client (machine that you are going to SSH from and run the installation command) needs to be connected to the same LAN.
  • You need a USB drive that you can wipe and convert into an installation media.
  • You need some existing machine running Arch Linux. This can be your client machine, or some other machine, or potentially a VM.
  • (optional): Server should have a static local IP configured in your router’s DHCP settings.
    • Otherwise connecting to the server will require finding its IP address again after every reboot.

General idea

We are going to create a custom Arch installer live USB that will automatically enable SSH access to the installation environment through our personal SSH key.

We will then insert this live USB, boot up our server, connect to it over SSH, and do the usual process for installing Arch. Before finishing and rebooting to the installed system, we will configure SSH access to that system as well.

Step 1: Preparing the live USB

We will follow Installation on a headless server.

First log in to your existing Arch Linux machine. Then install archiso:

$ sudo pacman -S archiso

Create a profile for your custom live USB, starting from a copy of the bundled releng profile:

$ cp -r /usr/share/archiso/configs/releng/ myarchiso

Create the directory for your configuration files inside myarchiso:

$ mkdir -p myarchiso/airootfs/var/lib/cloud/seed/nocloud
$ cd myarchiso/airootfs/var/lib/cloud/seed/nocloud

Prepare your configuration files here (these use the cloud-init system).

meta-data should be empty:

$ printf "" > meta-data

Write the following into user-data:

#cloud-config
users:
  - name: root
    ssh_authorized_keys:
      - ssh-ed25519 _XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX_

WARNING: first line is not a comment, it is required for this to work.

Replace _XXX... with your public SSH key. If you are not using ed25519, replace the schema as well (e.g. to ssh-rsa).

Then write the following into network-config:

version: 2
config: disabled

All set! We are ready to build our custom live USB image. Navigate back to the directory containing myarchiso and run:

$ sudo mkarchiso -v -r -w /tmp/archiso-tmp -o . ./myarchiso

This should produce a file named like archlinux-2025.10.12-x86_64.iso in your working directory. Burn it to your USB drive using dd (replace of= parameter with your USB block device):

$ sudo dd bs=4M if=archlinux-2025.10.12-x86_64.iso of=/dev/sdX conv=fsync oflag=direct status=progress

Once this succeeds, we are ready to actually install to our destination server.

Step 2: Installation

Insert the live USB into the server and boot it up (or reboot it). Give it some time to boot into the installation environment (~20-30 seconds), and try SSH’ing to it from your client machine (this is the first moment of truth):

$ ssh root@YOUR_SERVER_IP

If everything goes well, you should see the welcome message from the installation media and get a remote shell. If something doesn’t go well, your options are a bit limited:

  • If you get a password prompt for root: this means the SSH server is running (good!) but there is some issue with the public key config you have provided. You can go back to “preparing live USB” and try again. I actually hit this because I didn’t include the #cloud-config line in user-data, thinking it was a comment…
  • If you get Connection refused, No route to host, or something along these lines, this is not great. There is high chance that your server did not boot into the live USB for some reason. You may need to connect a keyboard and monitor to debug :(.

Let’s move on assuming you were lucky and you got a shell running. Follow the instructions in Installation Guide as you normally would, but make sure to do some additional steps:

When installing packages via pacstrap (or later via pacman after chroot’ing into the new system), make sure to install the software you will be using for networking and an SSH server. I am using networkmanager and openssh here. Enable both of them via systemctl on the new system. I needed to pass an additional -S flag to arch-chroot to do this.

# systemctl enable NetworkManager
# systemctl enable sshd

Edit /etc/ssh/sshd_config, setting PasswordAuthentication no, then add your client’s public SSH key to /root/.ssh/authorized_keys. The format is exactly the same as e.g. ~/.ssh/id_ed25519.pub on your client machine.

Once that’s done, there is one last step remaining.

Step 3: Bootloader

Our new system needs a bootloader, like usual. If you are confident in your bootloader configuration skills, you can ignore this section and do what you normally do. I will describe what I did.

I chose systemd-boot, for no particular reason except that it seemed actively maintained and reasonably simple. I have also used rEFInd in the past successfully, so I can vouch for that.

If you choose systemd-boot as well, follow the official manual. The bulk of it happens by just running:

# bootctl install

I have edited my /boot/loader/loader.conf to look like:

default         arch.conf
timeout	        4
console-mode	max
editor	        no

And created the actual config file at /boot/loader/entries/arch.conf:

title	Arch Linux
linux	/vmlinuz-linux
initrd	/initramfs-linux.img
options root=PARTUUID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX rw

You can determine your root partition PARTUUID by running blkid.

After this is done, reboot the machine. If everything went well, you should be now able to SSH into the installed system.

If the boot fails

If something didn’t go well at the bootloader step, you may be still able to recover if you are able to boot into the live USB again.

I have found that if systemd-boot fails to boot, the machine boot sequence (on the UEFI level) will fall back to other available UEFI executables, which should normally automatically include your live USB. That said, I am not an expert on this, and cannot say if it is true for all (or even most) modern machines.

Once you are booted to your live USB, you can “continue” your installation by mounting your block devices under /mnt according to your partitioning, then running arch-chroot -S /mnt. Once you are in this environment you can try to reconfigure or reinstall the bootloader. If you are lucky, you may even see some useful error messages in journalctl -xr.