Installing Arch Linux on a headless server
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-configline inuser-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.