
Hacker News · Feb 28, 2026 · Collected from RSS
Article URL: https://a-cup-of.coffee/blog/ostree-bootc/ Comments URL: https://news.ycombinator.com/item?id=47189625 Points: 8 # Comments: 1
IntroductionFor several years, I’ve been looking to manage my system configuration “As-code” to ensure reproducibility and consistency across my environments. The primary goal was to install my work laptop, but I also need to install Linux servers (without Kubernetes, so Talos isn’t an option).Initially, I used Packer to generate a virtual machine image, which I would then clone onto the disk of the machine I wanted to configure. It worked very well for server templates, but for a dev machine, it was a bit of a patchwork solution. On top of that, I decided to look for a Packer alternative because of Hashicorp’s licensing changes (a decision I still struggle to accept!).NixOS was an excellent replacement for a while, but I ran into several problems without having the necessary skills to solve them. I migrated to Fedora Silverblue, another immutable distribution in which I have more confidence. I found the comfort of a classic Linux installation while benefiting from the advantages of an immutable system.NoteQuick side-note: I’ll be talking a lot about OSTree in the context of CoreOS and Fedora Silverblue, but this technology isn’t exclusive to these distributions. We can also mention Fedora CoreOS, Endless OS, and even Podman’s virtual machine when on macOS or Windows.But I feel like I’m getting ahead of myself, so let’s start at the beginning.OSTree: Git for FilesystemsOSTree is often described as “Git for filesystems”. It enables versioning, distribution, and atomic deployment of Linux systems. Rather than managing packages individually, OSTree stores complete system snapshots, making updates and rollbacks easier.It’s based on ComposeFS, whose primary focus is ensuring data integrity. It relies on EROFS (Enhanced Read-Only File System) to guarantee that data won’t be corrupted and to store file metadata. It natively performs data deduplication and LZ4 compression.For the user, this is completely transparent.❯ mount | grep -e "overlay" -e "erofs" composefs on / type overlay (ro,relatime,seclabel,lowerdir+=/run/ostree/.private/cfsroot-lower,datadir+=/sysroot/ostree/repo/objects,redirect_dir=on,metacopy=on) lowerdir is the read-only directory (composefs) containing file metadata, and datadir is the directory containing the data (erofs).The data (in /sysroot/ostree/repo/objects) is stored in a dedicated directory that contains all system versions. Each version is identified by a hash, similar to Git.❯ ls /ostree/repo/ config extensions objects refs state tmp ❯ ls /ostree/repo/objects/05/ 02404180f5f1f775c1dc71850f19339064d281b433ec340730f96be2aa9c4f.file 5e77706a79f15f1c6b13713c0a05e8aca051ebb40bce01832b5ce0145ee3cc.file c01726f16a1c315014f946ee821e27b646536dae6aa70f39ed96eee0bea6c7.file 0fff529c3a948b1f56d0973eca5f840a1459c5ef43806f3c451f2fd835ebe2.file # ... The comparison with Git doesn’t stop there - OSTree allows you to create commits, new versions of our system, and switch between these versions just like you would with Git commits (git commit and git checkout).Let’s look at a Silverblue laptop I recently installed, for example: ostree-image-signed:docker://ghcr.io/ublue-os/bluefin-dx:latest Digest: sha256:7aabc7db3c3212ab3efd4a93dd895ee09c82a7af8d7c2e952bfb80f0058110a6 Version: latest-42.20251010.1 (2025-10-10T04:58:09Z) Diff: 36 upgraded, 3 added LayeredPackages: brightnessctl btop emacs erofs-utils gammastep gh ghostty kubectl matugen niri pavucontrol pcsc-tools quickshell-git trayscale vimiv wl-mirror zoxide ● ostree-image-signed:docker://ghcr.io/ublue-os/bluefin-dx:latest Digest: sha256:55481755d5d9ae678150b86962d75d15dd8ba2709664a64427197d5cdd083140 Version: latest-42.20251008 (2025-10-08T02:20:33Z) LayeredPackages: brightnessctl btop emacs gammastep gh ghostty kubectl matugen niri pavucontrol pcsc-tools quickshell-git trayscale vimiv wl-mirror zoxide I have 2 commits identified by their hash (Digest). I’m on the older one (bottom with the ● marker), but I can easily switch to the newer one by restarting my system (atomic method) or by using the rpm-ostree apply-live command to apply the update without restarting.In addition to seeing the differences between versions (36 upgraded packages, 3 new ones), we can also see the additional packages I’ve installed on top of the base image (LayeredPackages). I can also ask ostree to display the commit content, just like I would with git show.$ ostree admin status default 5ef5958f30a0ba985961f1a9e1e8a672287ad5b67e8092bce724cf9c72147484.0 (staged) origin: <unknown origin type> * default e595112738655e363e10ecbdb9378adcd6ebaebc23c1113c4d980e6b71e30b17.0 origin: <unknown origin type> $ ostree ls --repo=/sysroot/ostree/repo e595112738655e363e10ecbdb9378adcd6ebaebc23c1113c4d980e6b71e30b17 / d00555 0 0 0 / l00777 0 0 0 /bin -> usr/bin l00777 0 0 0 /home -> var/home l00777 0 0 0 /lib -> usr/lib l00777 0 0 0 /lib64 -> usr/lib64 l00777 0 0 0 /media -> run/media l00777 0 0 0 /mnt -> var/mnt l00777 0 0 0 /opt -> var/opt l00777 0 0 0 /ostree -> sysroot/ostree l00777 0 0 0 /root -> var/roothome l00777 0 0 0 /sbin -> usr/sbin l00777 0 0 0 /srv -> var/srv d00755 0 0 0 /boot d00755 0 0 0 /dev d00755 0 0 0 /proc d00755 0 0 0 /run d00755 0 0 0 /sys d00755 0 0 0 /sysroot d01777 0 0 0 /tmp d00755 0 0 0 /usr d00755 0 0 0 /var Yes, since hashes are calculated differently between ostree and rpm-ostree, they don’t match, so I have to retrieve the equivalent hash with ostreeThe possibilities are pretty wild from here. I can do ostree checkout, ostree commit, ostree diff, etc. The Git inspiration is really omnipresent (and that’s a good thing). In short, OSTree’s advantages are numerous, such as:Atomicity: Updates are applied in a single operation at reboot, reducing the risk of inconsistency.Easy rollback: In case of problems, it’s possible to return to a previous system version (it creates a boot menu entry at each update).Version management: Each system state is versioned, making tracking easierEfficient distribution: We rely on a known and proven distribution method - more on that later!But of course, like any immutable system, there are mutable parts (otherwise, we couldn’t create any configuration files). OSTree handles this with “overlays” (actually, we use OverlayFS) that allow a read-write filesystem to be layered on top of the immutable system. For example, the /etc and /var directories are writable, while the rest of the system is read-only.To give some detail, it’s /var that is writable, and mutable directories will have symbolic links pointing to subdirectories of /var:/home → /var/home/opt → /var/opt/srv → /var/srv/root → /var/roothome/usr/local → /var/usrlocal/mnt→ /var/mnt/tmp → /sysroot/tmp/etc is also writable, but it’s managed a bit differently. OSTree uses a technique called “etc overlay” to handle modifications in /etc. When an update is applied, OSTree compares files in the new version with those in /etc and applies changes intelligently, preserving local modifications as much as possible.Thus, there’s the /usr/etc folder containing the immutable version of configuration files, and /etc which is the mutable directory. If I modify a file in /etc and ask OSTree to compare with the new version, it will show me the differences and preserve my local modifications.❯ ls /usr/etc/motd /usr/etc/motd ❯ sudo ostree admin config-diff | grep motd # No diff ❯ echo "Hello, World!" > /etc/motd ❯ sudo ostree admin config-diff | grep motd M motd I really like this approach and find it reassuring about OSTree’s ability to manage service configurations without forcing us to never modify them.A Package Manager for OSTree: rpm-ostreeOSTree manages the files that make up the system, but what does that mean for packages that want to write to /usr or /lib? That’s why integration with the package manager is needed. In the case of RedHat OSes, it’s rpm-ostree that replaces dnf and yum.❯ dnf install neovim Error: this bootc system is configured to be read-only. For more information, run `bootc --help`. As soon as we try to install a package with dnf, we’ll get an error. We need to use rpm-ostree to manage packages.❯ rpm-ostree install neovim Checking out tree 39fd9fc... done Resolving dependencies... done Will download: 17 packages (55.1 MB) Downloading from 'updates'... done Downloading from 'fedora'... done Importing packages... done Checking out packages... done Running systemd-sysusers... done Running pre scripts... done Running post scripts... done Running posttrans scripts... done Writing rpmdb... done Writing OSTree commit... done Staging deployment... done Freed: 126.9 MB (pkgcache branches: 0) Added: compat-lua-libs-5.1.5-28.fc42.x86_64 erofs-utils-1.8.10-1.fc42.x86_64 inotify-tools-4.23.9.0-4.fc42.x86_64 intel-qpl-1.7.0-1.fc42.x86_64 libluv-1.51.0.0-2.fc42.x86_64 libtsan-15.2.1-1.fc42.x86_64 libvterm-0.3.3-5.fc42.x86_64 lua5.1-lpeg-1.1.0-5.fc42.x86_64 luajit-2.1.1748459687-2.fc42.x86_64 luajit2.1-luv-1.51.0.0-2.fc42.x86_64 neovim-0.11.4-1.fc42.x86_64 nodejs-1:22.19.0-2.fc42.x86_64 nodejs-docs-1:22.19.0-2.fc42.noarch nodejs-full-i18n-1:22.19.0-2.fc42.x86_64 nodejs-libs-1:22.19.0-2.fc42.x86_64 nodejs-npm-1:10.9.3-1.22.19.0.2.fc42.x86_64 ripgrep-14.1.1-2.fc42.x86_64 tree-sitter-cli-0.25.10-1.fc42.x86_64 unibilium-2.1.2-3.fc42.x86_64 xsel-1.2.1-8.fc42.x86_64 Changes queued for next boot. Run "systemctl reboot" to start a reboot After my package has been installed, rpm-ostree indicates that changes will be applied at the next reboot. Indeed, rpm-ostree creates a new OSTree commit with the added package, but doesn’t modify the running system. This is an important step to guarantee update atomicity.If I still want to apply changes immediately, I can use the rpm-ostree apply-live command which will apply changes without restarting the system (but some modifications may require a reboot to be fully effective).And conversely, if I want to revert the modifications, that’s also possible:❯ rpm-ostree rollback Bootc: Linux in Container ModeYes, because if I have to go through Fedora’s standard w