Fedora IoT (Internet of Things) is a Fedora Linux edition dedicated to address edge computing challenges. Although this is a big topic, in this example I'm considering an edge device to be a relatively small computing device that processes data near where the data is produced and runs mostly unattended.
For my edge case, I use a Raspberry Pi 4 with 2GB RAM to power a small home application that runs in a container. This device runs in a hard-to-access corner, has no monitor or keyboard attached, and connects to the network using WiFi. Fedora IoT fits nicely as an operating system for these requirements. This article explains why and how to get started with it.
Why Fedora IoT
Fedora IoT is an immutable, minimal operating system that's well suited for small edge devices. Because edge devices often run remotely and unattended, Fedora IoT provides features that help devices work reliably and autonomously. Some of these features include:
- Immutable operating system: Fedora IoT deploys the operating system as an image, locking important parts of the root filesystem as read-only. This feature prevents users or applications from making changes to the base operating system, improving its security and reliability by avoiding random changes that could cause issues.
- Atomic updates: Because Fedora IoT deploys the base operating system as an image, users cannot update individual packages. The system performs upgrades to the entire base operating system as a whole, in a single atomic operation that is effective only after a reboot.
- Rollback: The system preserves older versions of the base operating system, allowing it to roll back to a previously working configuration if there is an issue with an update.
- Greenboot: This is a health-check framework that ensures critical operating systems components and end-user workloads are working properly at boot time. In case of a health-check failure, it can roll back to a known-good configuration to make the system resilient.
- Container-focused: Because the base operating system is immutable, Fedora IoT encourages running workloads as containers. You can still layer packages on top of the base operating system if needed, but running containers is preferred to maintain the operating system's stability and reliability.
To support some of these features, Fedora IoT uses rpm-ostree, which enables the image-based operating system. It's the same technology behind other immutable operating systems including Fedora Silverblue.
[ Learn how to install containerized applications on Fedora Silverblue. ]
Fedora IoT is also the upstream version of Red Hat Enterprise Linux (RHEL) for Edge, which means that development done here may ultimately end up in RHEL. At the time I am writing this article, RHEL for Edge does not yet support ARM devices, making Fedora IoT a natural choice for the Raspberry Pi.
For more information about Fedora IoT, consult the official documentation.
Install the image installer tool
You can install Fedora IoT in several ways. For the Raspberry Pi, I recommend using the raw image as the easiest way to get started. This method allows you to copy the image to an SD card and boot the Raspberry Pi directly from it.
[ Get the guide to installing applications on Linux. ]
First, download the raw
aarch64 architecture image from the Fedora downloads page.
$ curl -LO https://download.fedoraproject.org/pub/alt/iot/37/IoT/aarch64/images/Fedora-IoT-37-20221118.0.aarch64.raw.xz
Then, to copy this image to the SD card while adding initial customizations to it, use the
arm-image-installer program available in the standard Fedora 37 repository.
$ sudo dnf install arm-image-installer
You need to run this on a standard Fedora Workstation or Server machine.
Create the bootable SD card
Insert the target SD card in the machine where you downloaded the image installer. Use the command
lsblk to get the SD card device name. In my case it's
$ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS sr0 11:0 1 1024M 0 rom mmcblk0 179:0 0 28.8G 0 disk ├─mmcblk0p1 179:1 0 200M 0 part └─mmcblk0p2 179:2 0 28.6G 0 part zram0 251:0 0 7.6G 0 disk [SWAP] vda 252:0 0 60G 0 disk ├─vda1 252:1 0 600M 0 part /boot/efi ├─vda2 252:2 0 1G 0 part /boot └─vda3 252:3 0 58.4G 0 part /home /
Next, use the image-installer software to copy the downloaded image onto the SD card and make it bootable. I'm using these options:
--image: Set to the downloaded image
--media: Set to the device ID of your SD card
--addkey: Use to copy an SSH public key for authentication
--norootpass: Do not allow root login using a password
--resizefs: Resize the filesystem to occupy the entire SD card
--target=rpi4: Install the appropriate bootloader for Raspberry Pi 4
-y: Don't ask for confirmation
WARNING: This operation overwrites everything in the SD card. Make sure you don't have anything important on it.
Run the command using
sudo to allow writing to a block device:
$ sudo arm-image-installer \ --image=Fedora-IoT-37-20221118.0.aarch64.raw.xz \ --media=/dev/mmcblk0 \ --addkey=/home/ricardo/.ssh/id_rsa.pub \ --norootpass \ --resizefs --target=rpi4 -y ===================================================== = Selected Image: = Fedora-IoT-37-20221118.0.aarch64.raw.xz = Selected Media : /dev/mmcblk0 = U-Boot Target : rpi4 = Root Password will be removed. = Root partition will be resized = SSH Public Key /home/ricardo/.ssh/id_rsa.pub will be added. ***************************************************** ******** WARNING! ALL DATA WILL BE DESTROYED ******** ***************************************************** [...] = Raspberry Pi 4 Uboot is already in place, no changes needed. = Removing the root password. = Adding SSH key to authorized keys. = Installation Complete! Insert into the rpi4 and boot.
When the command finishes copying the image and customizing it, it also installs the bootloader. At this point, you could eject the SD card and boot your Raspberry Pi. For this example, I'll configure the WiFi network first.
Add WiFi networking to the image
If your Raspberry Pi connects to the network using a cable or it is connected to a monitor and keyboard, you can skip this step. I need the Raspberry Pi to connect to the network using WiFi, so before I use the SD card to boot the device, I'll add a configuration file with the required WiFi profile, so it automatically connects to the network on first boot.
To do this, first mount the SD card root partition to
$ sudo mount /dev/mmcblk0p3 /mnt
Then, switch into the Network Manager
system-connections directory in the ostree filesystem:
$ cd /mnt/ostree/deploy/fedora-iot/deploy/d06...0f.0/etc/NetworkManager/system-connections/
Note: I truncated the full directory name due its length.
Finally, create a Network Manager connection profile to connect to your WiFi network. Set the proper
ssid and password
psk fields for your network. Also, set
autoconnect=true to automatically connect to the network when the Raspberry Pi starts:
$ sudo vi wifi01.nmconnection [connection] id=wifi01 type=wifi permissions= autoconnect=true [wifi] mac-address-blacklist= mode=infrastructure ssid=wifissid [wifi-security] auth-alg=open key-mgmt=wpa-psk psk=******************************************** [ipv4] dns-search= method=auto [ipv6] addr-gen-mode=stable-privacy dns-search= method=auto [proxy]
Save this file, change its permissions to
600, and unmount the SD card.
$ sudo chmod 600 wifi01.nmconnection $ cd $ sudo umount /mnt
You can now remove the SD card from your computer.
[ Get the Getting started with Raspberry Pi cheat sheet. ]
Boot the Raspberry Pi
Insert the SD card into the Raspberry Pi and start it. After a few seconds, the operating system will be up. If everything works correctly, the Raspberry Pi connects to the WiFi network (or even a wired network) and obtains an IP address from DHCP. You can check your router software for the IP address assigned or run nmap on your local network to identify it.
Use this IP address to connect to the Raspberry Pi using the SSH key you added to the image. For now, connect as user
root. You'll change it later.
$ ssh -i /home/ricardo/.ssh/id_rsa firstname.lastname@example.org Boot Status is GREEN - Health Check SUCCESS [root@localhost ~]#
Check which version (commit) of
ostree you're using:
[root@localhost ~]# rpm-ostree status State: idle Deployments: ● fedora-iot:fedora/stable/aarch64/iot Version: 37.20221118.0 (2022-11-18T17:32:21Z) Commit: d06a0d1d93cd2e3ebe1b744bb16c23087a001f3116579bdb0f22dedcf755250f GPGSignature: Valid signature by ACB5EE4E831C74BB7C168D27F55AD3FB5323552A
Stage the update to the system image using
[root@localhost ~]# rpm-ostree upgrade ... Receiving objects; 99% (9764/9808) 3.5 MB/s 367.6 MB 1662 metadata, 8146 content objects fetched; 359573 KiB transferred in 114 seconds; 655.2 MB content written Receiving objects; 99% (9764/9808) 3.5 MB/s 367.6 MB... done Staging deployment... done Upgraded: ... TRUNCATED OUTPUT ... Run "systemctl reboot" to start a reboot
rpm-ostree downloads and stages the update, but the system is still running the current image. To complete the update, reboot the system:
[root@localhost ~]# systemctl reboot
Reconnect to the Raspberry Pi and verify the current image version:
[root@localhost ~]# rpm-ostree status State: idle Deployments: ● fedora-iot:fedora/stable/aarch64/iot Version: 37.20230306.0 (2023-03-06T16:22:46Z) Commit: 91d2e51a29e8f7b81287d1abe0009ff288c8d435873225191c5ab00aea12dc22 GPGSignature: Valid signature by ACB5EE4E831C74BB7C168D27F55AD3FB5323552A fedora-iot:fedora/stable/aarch64/iot Version: 37.20221118.0 (2022-11-18T17:32:21Z) Commit: d06a0d1d93cd2e3ebe1b744bb16c23087a001f3116579bdb0f22dedcf755250f GPGSignature: Valid signature by ACB5EE4E831C74BB7C168D27F55AD3FB5323552A
The Raspberry Pi is running the latest version of Fedora IoT, but the system kept the previous image in case you need to roll back.
You have a basic Fedora IoT system running on your Raspberry Pi with the latest updates. The system is ready to use but still requires some additional configuration. For example, you need to change the hostname and add a different user so you don't need to connect using
In the next article, I'll use Ansible to configure Fedora IoT, and later I'll show how to use Greenboot to run health checks and manage the boot process.