How to install Fedora on a Headless Raspberry Pi

The complete guide to installing Fedora on a Headless Raspberry Pi 3 or 4 (no keyboard, monitor, or serial cable needed)

Roberto Meléndez
Geek Culture
7 min readMay 26, 2021

--

Vector by Vecteezy

Overview

I couldn’t find an updated Fedora installation guide for Raspberry Pi that was completely headless. The ones I found didn’t work or required a serial cable, which defeats the purpose. After a lot of research and a process of trial and error, I successfully installed Fedora Server 34 on a headless Raspberry Pi 3 and 4.

In this step-by-step guide, I’ll show you how to download the correct image, mount it, modify it to suit our needs, and install the custom image on a microSD card ready for your Raspberry Pi. As a bonus at the end, I’ll share the steps to set up a Wi-Fi connection.

Prerequisites

To follow this guide, you will need:

  • Fedora machine with microSD card reader
  • Fedora ARM raw image
  • A Raspberry Pi 3 or 4 with wired Internet connectivity

Step 1 — Downloading Fedora ARM image

For ARMv7 (32 bits) images, go to Fedora ARM website. If you prefer 64-bit images like me, they are a bit hidden. Instead, visit Fedora Wiki and choose your type: Workstation, Server, or Minimal.

In my environment, I ran this command to download the latest Fedora Server 64-bit raw image:

curl -L -O https://download.fedoraproject.org/pub/fedora/linux/releases/34/Server/aarch64/images/Fedora-Server-34-1.2.aarch64.raw.xz

Step 2 — Preparing the raw image

First, uncompress the image:

xz --decompress Fedora-Server-34-1.2.aarch64.raw.xz

The above command will replace the 789 MB .xz file for a 7 GB .raw file.

Next, list the partitions in the raw image with fdisk:

$ fdisk -l Fedora-Server-34-1.2.aarch64.raw 
Disk Fedora-Server-34-1.2.aarch64.raw: 7 GiB, 7516192768 bytes, 14680064 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xd17792e4
Device Boot Start End Sectors Size Id Type
Fedora-Server-34-1.2.aarch64.raw1 * 2048 1230847 1228800 600M 6 FAT16
Fedora-Server-34-1.2.aarch64.raw2 1230848 3327999 2097152 1G 83 Linux
Fedora-Server-34-1.2.aarch64.raw3 3328000 14680063 11352064 5.4G 8e Linux LVM

Our image has three partitions. The .raw1 is the bootloader partition. The .raw2 is the Linux boot partition (id 83). Finally, the .raw3 is the partition we want, a Linux LVM partition (id 8e) where Fedora is installed.

Now, with that information, we could just calculate the mount offset as follows:

sector size (512) x start sector (3328000) = 1703936000

This means that we’d need to mount the image with an offset of 170393600 to be mounted at the right place. However, if we did that it’d fail:

$ sudo mount -o loop,offset=1703936000 Fedora-Server-34-1.2.aarch64.raw /mnt/raw3
mount: /mnt/raw3: unknown filesystem type 'LVM2_member'.

To solve this problem, we need a tool like kpartx. This utility creates a virtual device in /dev/mapper that we can manipulate as a real device. Run the following command to add a device verbosely:

$ sudo kpartx -a -v Fedora-Server-34-1.2.aarch64.raw 
add map loop0p1 (253:0): 0 1228800 linear 7:0 2048
add map loop0p2 (253:1): 0 2097152 linear 7:0 1230848
add map loop0p3 (253:2): 0 11352064 linear 7:0 3328000

Then verify the new partitions in /dev/mapper:

$ ls -l /dev/mapper/
crw-------. 1 root root 10, 236 May 14 11:20 control
lrwxrwxrwx. 1 root root 7 May 14 18:16 fedora_fedora-root -> ../dm-3
lrwxrwxrwx. 1 root root 7 May 14 18:16 loop0p1 -> ../dm-0
lrwxrwxrwx. 1 root root 7 May 14 18:16 loop0p2 -> ../dm-1
lrwxrwxrwx. 1 root root 7 May 14 18:16 loop0p3 -> ../dm-2

Finally, create a directory and mount the LVM partition to the new directory:

sudo mkdir /mnt/raw3
sudo mount /dev/fedora_fedora/root /mnt/raw3

Step 3 — Working directly within the image

It’s time to start modifying the image. To do this we’ll use chroot to change the working root of our session to the one from the image. For this emulation to work between architectures, we need to install qemu-user-static and restart systemd-binfmt.service:

sudo dnf install qemu-user-static
sudo systemctl restart systemd-binfmt

Chroot to the mounted disk image and start a shell:

sudo chroot /mnt/raw3 /bin/bash

Make sure the architecture is aarch64 and not x86_64:

# uname -a
Linux fedora 5.11.19-200.fc33.x86_64 #1 SMP Fri May 7 14:10:27 UTC 2021 aarch64 aarch64 aarch64 GNU/Linux

Now set up a local user that we’ll use to connect via SSH later. The following commands create a group and user called pi. Then the user will get a UID of 1000 and be assigned to the pi and wheel groups:

groupadd pi
useradd -g pi -G wheel -m -u 1000 pi

Create the .ssh directory, the authorized_keys file and assign proper permissions:

mkdir /home/pi/.ssh
chmod 700 /home/pi/.ssh
touch /home/pi/.ssh/authorized_keys
chmod 600 /home/pi/.ssh/authorized_keys
chown -R pi.pi /home/pi/.ssh/

Then add your Fedora machine public key (~/.ssh/id_rsa.pub) to the authorized_keys file.

Since our new user belongs to the wheel group, allow this group to use sudo without password:

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

Also, Fedora prompts you to finish the setup on the first boot. To avoid that, disable the initial setup:

unlink /etc/systemd/system/multi-user.target.wants/initial-setup.service
unlink /etc/systemd/system/graphical.target.wants/initial-setup.service

That’s all we need to change. Exit the chroot and unmount the disk image:

exit
sudo umount /mnt/raw3

Now we need to delete the loop0 device, but it contains a Linux LVM partition:

$ sudo pvscan
PV /dev/mapper/loop0p3 VG fedora_fedora lvm2 [5.41 GiB / 0 free]
Total: 1 [5.41 GiB] / in use: 1 [5.41 GiB] / in no VG: 0 [0 ]

Thus, deactivate the logical volume inside the volume group fedora_fedora:

$ sudo vgchange --activate n fedora_fedora
0 logical volume(s) in volume group “fedora_fedora” now active

Then delete the virtual device:

$ sudo kpartx -d Fedora-Server-34-1.2.aarch64.raw
loop deleted : /dev/loop0

Step 4 — Installing the modified image

All that is left are two time-consuming tasks: image compression and installation on a microSD card.

Compress the raw disk image to a .xz file, but this time keep the .raw file:

xz --compress Fedora-Server-34-1.2.aarch64.raw --keep

I recommend you keep the raw file if you want to make incremental changes in the future. Otherwise, remove the --keep parameter.

This command will take a while.

Finally, copy the modified disk image to a microSD card:

sudo arm-image-installer --image=Fedora-Server-34-1.2.aarch64.raw.xz --media=/dev/sdb --target=rpi3 --norootpass --resizefs -y

For Raspberry Pi 4, it’s the same command, just replace the target to --target=rpi4.

This command will take some time as well.

Step 5 — Validation

Let’s confirm that we can access our new machine. Insert the microSD card into your Raspberry Pi and wait a couple of minutes to be ready. Then in your Fedora machine (or any other computer connected to your home network) run nmap or a similar tool to find out the dynamic IP address assigned to your Raspberry Pi (replace your CIDR range accordingly):

$ sudo nmap -sn 192.168.0.0/24
Nmap scan report for 192.168.0.126
Host is up (0.000078s latency).
MAC Address: E4:5F:01:AA:BB:CC (Raspberry Pi Trading)

Look for Raspberry Pi Trading or Raspberry Pi Foundation in the MAC address. Then use that IP address and the user you created to SSH into your Raspberry Pi:

$ ssh pi@192.168.0.126
The authenticity of host '192.168.0.126 (192.168.0.126)' can't be established.
ECDSA key fingerprint is SHA256:zx....
ECDSA key fingerprint is MD5:13:ce:...
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.0.126' (ECDSA) to the list of known hosts.
Web console: https://fedora:9090/ or https://192.168.0.126:9090/
[pi@fedora ~]$

Congratulations! 👏 You successfully connected to your new Fedora Server on your Raspberry Pi!

As always, update your system right away:

[pi@fedora ~]$ sudo dnf update -y

[Optional] — Setting Up Wi-Fi

By default, Wi-Fi does not work out of the box in Fedora Server because wpa_supplicant is not included. In fact, there is an open Bugzilla ticket since 2019.

To work around this problem, install the missing package, enable it and restart the machine:

[pi@fedora ~]$ sudo dnf install wpa_supplicant -y
[pi@fedora ~]$ sudo systemctl enable wpa_supplicant
[pi@fedora ~]$ sudo shutdown -r now

Wi-Fi will not work if the Raspberry Pi is not rebooted.

Once the Raspberry Pi is back up and running, list the available networks:

[pi@fedora ~]$ nmcli device wifi list

Locate your network on the list and connect to it:

[pi@fedora ~]$ sudo nmcli device wifi connect <YOUR_SSID> --ask
Password: ••••••••
Device 'wlan0' successfully activated with '15b5-XXX-XXX-XXX-495'.

Now, if you list the device status, you’ll see Wi-Fi connected:

[pi@fedora ~]$ nmcli device
DEVICE TYPE STATE CONNECTION
eth0 ethernet connected Wired connection 1
wlan0 wifi connected YOUR_SSID

Wrapping Up

I hope this guide was helpful. Now you should have a working Raspberry Pi with Fedora installed. Even though it was intended for Fedora, you can adapt the process to other Linux distros. Let me know if you find any obstacles along the way or if you have any questions/comments please reach out and I’ll help you. Enjoy your pi!

--

--

Roberto Meléndez
Geek Culture

Engineer @devo_Inc, an Enterprise Logging and Security Analytics unicorn | Tech enthusiast | Traveler | Music Lover | Mexican 🔗 linkedin.com/in/rcmelendez