Skip to content

Juniper: Opinionated bootc Image for Raspberry Pi 4/5

software5 min readCode Repository ↗

Juniper is an open-source, bootc-based AlmaLinux 10 OS for the Raspberry Pi. The main image is built for development, with Homebrew, Podman, Distrobox and Tailscale included. Once your software is ready, you can build an appliance image on Juniper minimal and switch the Pi to it, with Podman containers managed by systemd through Quadlet files. After the Pi joins Tailscale's mesh VPN, the firewall restricts inbound access to Tailscale traffic.

1 Introduction

Atomic Linux operating systems, such as those built with bootc, have grown a lot since their inception a handful of years ago. Popular systems from Universal Blue, such as Bluefin, Bazzite and Aurora, follow a related approach to image-based, atomic updates. After using uCore on a server and becoming familiar with bootc, I quickly concluded that it would have several advantages for edge computers such as Raspberry Pis: atomic deployments reduce the risk of partially applied system updates, unchanged image layers can be reused to reduce downloads, and the same OS image can be deployed across a fleet.

AlmaLinux's work on an experimental bootc variant of their OS for the Raspberry Pi made this possible. Juniper is open source, released under the Apache License 2.0.

Juniper login on a Raspberry Pi 5: the berry logo, a system summary, and the Tailscale and update status
Fig. 1. Live SSH login output from a Raspberry Pi 5 running Juniper, captured on 13 October 2026. Example network addresses substituted.

2 The Three Junipers

I felt that a series of bootable containers for developing edge systems on the Raspberry Pi 4 and 5 would be useful to others. Hence Juniper, which currently comes in three versions. The two headless images have been tested on a Pi 5 with microSD storage; support for the other boards and boot media remains unverified on hardware.

The standard Juniper image is designed in the Universal Blue style, and even uses their version of Homebrew. It also comes with Podman and Distrobox. Homebrew for packages and Distrobox for mutable container environments make it flexible and simple to develop on, with Podman for more reproducible container setups.

Then there is the minimal image. Once you have developed the software for your edge computer, the intention is that you switch to the minimal image and run your software in Podman containers using Quadlet files, which generate systemd services. I would even suggest setting up your own repository and CI/CD pipeline that uses Juniper minimal as a base and adds your packages, Quadlet files and workload health checks, creating a specialised OS image for your application. On a Juniper device, ujust switch IMAGE switches to that image and reboots into it.

Finally, for those who don't wish to develop on a headless machine, there is an experimental desktop using niri as the Wayland compositor. I recently started using Zirconium as my daily driver; its lightweight desktop inspired this variant. Juniper desktop is built and tested in CI but currently untested on hardware. I have ordered a micro-HDMI cable and will test it with a screen as soon as possible.

3 Advantages for Edge Computers

Juniper provides some distinct advantages for edge Raspberry Pis, such as those used for remote sensing and IoT applications, especially when they are in hard-to-access locations with limited or unreliable connectivity.

3.1 Small System Updates

Juniper's OS images are rechunked before release, organising their contents into reusable OCI layers. When updating, bootc can reuse layers already present on the device and download the changed layers. This can make over-the-air system updates much smaller than downloading the whole image, although the size depends on what changed. That is useful when a remote sensor has to keep data usage down because of cost or unreliable connectivity.

3.2 Deployment and Rollback

Juniper checks for signed OS updates daily and stages them for deployment. By default, a staged update is applied during a weekly reboot window, which can be changed or disabled with ujust update-schedule. The new deployment boots through the Raspberry Pi firmware's tryboot mechanism and is confirmed only if Juniper's boot health checks pass. If those checks fail, the Pi reboots into the previous deployment. You can add workload health checks so an update that breaks your application also triggers fallback. This reduces the risk of losing access to a remote device after an update, but it does not detect every possible fault or roll back application data stored under /var.

3.3 Tailscale

Tailscale, for anyone not familiar with it, is a WireGuard mesh VPN with a very generous free tier, and it is frankly brilliant. I am evangelical about Tailscale: running a network of computers that need to communicate securely is now incredibly easy. Controlling the mesh VPN with GitOps has made my life much easier, and the admin console is also very simple. On Juniper the firewall locks down inbound access after the Pi joins the tailnet, allowing traffic over Tailscale and its UDP transport port. Before that, SSH remains available over the local network so a failed join can be fixed. The example flashing config includes a placeholder for a Tailscale auth key; supplying your own key lets the Pi join automatically on first boot.

This has the rather obvious advantage of providing a clear and safe way for an edge computer to send data to, and receive data from, your network.

3.4 Root Filesystem Encryption

Setting encrypt: true in the flashing config requests LUKS2 encryption of the root filesystem on first boot. The unlock key is derived using a device key stored in the Raspberry Pi's OTP (one-time programmable) memory and, where available, the storage device's identity. This currently requires a Pi 5 with a bootloader EEPROM from 21 January 2026 or later; Pi 4 support is unverified. Unsupported configurations remain unencrypted, so check ujust pi-status after boot. An encrypted card removed from the Pi protects the data in the root filesystem, but the boot partition remains unencrypted and someone holding both the Pi and its card can still unlock it. Recovery if the board fails requires the private SSH or age key to which the recovery key was sealed.

4 Getting Started

See the GitHub repository and follow the instructions. The just flash helper currently requires Linux; the README also documents manually flashing a release disk image from any OS.

5 What's Next

Next, I want to test the desktop version on hardware and make flashing from Windows and macOS more convenient, ideally by adding Juniper to the official Raspberry Pi Imager image catalogue.

6 Acknowledgements

Juniper builds on AlmaLinux's bootc images for the Raspberry Pi, and on ideas from Universal Blue's Bluefin and Bazzite and from Zirconium.