Introducing Duranium: a more reliable postmarketOS

March 17, 20266 min. read

Two chickens found a phone running Duranium

Image-based updates are nothing to bawk at.

Duranium is an immutable variant of postmarketOS, built around the idea that your device should just work, and keep working. You shouldn't need to know what a terminal is to keep your device running.

"Immutable" means the core operating system is read-only and can't be modified while it's running. System updates are applied as complete, verified images rather than individual packages. Either the new image works, or the system falls back to the previous one automatically. No partially-applied state. No debugging audio when you need to make a phone call and no fussing with a broken web browser when you just want to doomscroll cat photos. It also means developers can reproduce the exact state of a user's device, making it much easier to track down and fix issues.

Reliability and ease of use take priority over flexibility. Some choices that make it robust also mean it has higher hardware requirements and won't run on every device that can boot postmarketOS. Not every device that can boot postmarketOS will be supported.

The package base for Duranium is shared with current versions of postmarketOS, and improvements flow into both. Think of it as a different deployment model on top, not a fork.

Duranium is still a work in progress. We are looking for testers, not people who need a reliable daily driver just yet. See the Help Wanted section at the end of this post if this interests you!

The initial proof-of-concept was funded by NLnet through the NGI initiative. Some ongoing development is funded through the postmarketOS Contributor Support Program.

The technical details

If the implementation details aren't your thing, feel free to skip to the end.

For full details on everything covered here, see the design document.

Tooling choices

Duranium is built on systemd's image-based OS tooling. If you want the full story on why postmarketOS ships systemd, that's covered here. Specifically: tools like systemd-sysupdate, systemd-repart, and systemd-verity-setup gave us A/B updates, partition management, and verity integration largely for free, which made it possible to build Duranium's core without reinventing that infrastructure.

So, where does everything live?

The OS lives in /usr, mounted read-only and cryptographically verified on every boot. Configuration lives in /etc. System state lives in /var. Your files live in /home. Everything outside /usr is writable and persistent.

Contrary to how some other immutable Linux operating systems handle /etc, it is not a read-only overlay with a writable layer on top. Instead, /usr ships a set of default config files, and systemd-tmpfiles creates symlinks from /etc back into /usr on first boot. This means that if you haven't touched a config file, it automatically reflects whatever the current image provides. Booting an older image gives you older defaults. If you want to customize something, you copy the file out of the factory in /usr into /etc, breaking the symlink, and then edit it. Your changes persist across updates. More details on this are available on the wiki.

Updates use A/B partition slots, but these are not the standard Android A/B slots since supporting those would add complexity to the design. When an update lands, it gets written to the inactive slot while your running system is completely untouched. On the next boot, the new slot gets a chance to prove itself. If it boots successfully, it becomes the new active slot. If it doesn't, the bootloader falls back to the previous one. You probably won't even notice.

Each /usr slot is allocated 5GB. EROFS, a compressed read-only filesystem, is used so a slot can actually hold more than 5GB of OS content. 5GB partitions for each A and B slot might seem like a lot, but this seems to be a good trade-off to help ensure future UIs and features should fit without needing to repartition down the road. Keep in mind that between two /usr slots, verity partitions, and the root filesystem, Duranium requires a meaningful amount of storage. It is not designed to run on every device that can boot postmarketOS.

Integrity and encryption

/usr is protected by dm-verity, which cryptographically verifies the entire partition on every read. If anything has been tampered with, the system refuses to boot. The hash is embedded in a UKI (Unified Kernel Image), so the verification chain starts from the UEFI bootloader. This means Duranium requires UEFI boot support on the device.

The root filesystem, where mutable user and OS data and configuration are stored, is encrypted with LUKS2. This is not optional.

Yes, encryption has a performance cost on constrained hardware. But phones, laptops, tablets, etc. get lost and stolen, and an OS that leaves user data unprotected by default is making a tradeoff that isn't worth making. Android has had encryption on by default for many years for exactly this reason.

The root filesystem for data is created as new LUKS volume on first boot or during factory reset. Initially it has a blank key, so it auto-unlocks on boot. This provides no real protection on its own, so the first-boot setup gives you the opportunity to replace it with a real passphrase. You can do the same at any point later without any complicated filesystem migration. If a factory reset is ever performed later, the encrypted partition is wiped and recreated from scratch.

The verification chain only matters if the bootloader itself can be trusted, which requires Secure Boot support. Secure Boot and verified boot are not yet implemented, but are planned. Some of the dependencies, particularly for phones, require additional upstream work.

But my phone doesn't have UEFI...

Duranium uses UEFI as its boot interface, which is standard on laptops and x86 hardware. For Android devices, U-Boot can provide the UEFI support. We learned pretty early on in postmarketOS's history that repartitioning Android devices is fraught with danger... in some cases it can brick a device. So, like mutable postmarketOS, Duranium on phones is installed to a GPT partition table embedded within the device's userdata partition. U-Boot can boot from these subpartitions via the blkmap command, which acts similar to losetup. This is how a full GPT layout fits onto a device that normally has Android's fixed partition table. On hardware that can be repartitioned normally, like laptops, it uses standard GPT partitions instead.

Not every Android device has U-Boot support yet, and getting a new device supported requires someone to upstream that work first, much like getting a device's kernel mainlined.

Installing software on an immutable OS

Since /usr is read-only at runtime, you can't install system packages the usual way using a system-level package manager (like apk). So what can you do?

Flatpak is the primary way to install applications on Duranium. It's a sandboxed application distribution system that works independently of the underlying OS. App permissions are managed through portals, frontends exist for all of the major mobile UI environments, and Flathub has a large and growing catalog of apps.

coldbrew works similarly to Homebrew, but pulls from Alpine Linux's binary package repositories. It installs software into your home directory, sandboxed via bubblewrap. Nothing installed through coldbrew can touch the core OS, so you can't accidentally break phone calls or audio by installing or updating coldbrew packages.

Those are the options that ship with Duranium by default. Nothing stops you from using other tools like Nix or Homebrew as well.

Support for systemd sysext images is planned, but needs more research.

Help wanted

Duranium is still under heavy development. That said, testing is very much appreciated, and there are plenty of ways to get involved.

Images are available at duranium.postmarketos.org. The wiki page has setup instructions and device support info. If you run into issues or want to follow along, come find us in #immutable:postmarketos.org on Matrix, or #postmarketos-immutable on OFTC (bridged to Matrix).

If you appreciate the work we're doing and want to support it, please consider donating via OpenCollective.

This blog post was written by Clayton. Header image by Clayton.