Bootc on Linux in 2026: Image-Mode RHEL and Fedora for Immutable Servers
Bootc packages a whole Linux OS as an OCI image, then upgrades RHEL and Fedora servers transactionally with signed digests and automatic rollback. A 2026 walkthrough for building, signing, and deploying image-mode servers you can actually roll back safely.
Bootc is a Linux tool that turns a standard OCI container image into a bootable, transactionally updated operating system, so you can build, ship, and upgrade RHEL and Fedora servers with the same Containerfile workflow you already use for applications. One artefact, one signature, one registry, and a system that either upgrades cleanly or rolls back on the next boot. In 2026, both Red Hat image mode for RHEL 10 and Fedora bootc are generally available, and the old attacker economics of "compromise a package, wait for dnf update" don't really work the way they used to.
Bootc packages an entire Linux OS as an OCI image; the boot filesystem is derived from a container layer, not from RPMs installed piecemeal on the target.
Red Hat image mode for RHEL 10 and Fedora bootc are GA in 2026, replacing rpm-ostree as the recommended path for new immutable server builds.
Upgrades are transactional: bootc upgrade stages a new deployment, and a failed boot automatically rolls back to the previous known-good image.
Signing bootc images with cosign and enforcing verification via /etc/containers/policy.json closes the "poisoned upgrade" attack path that legacy dnf pipelines leave open.
Persistent state is confined to /var and /etc; everything else is a read-only overlay you can attest against a known digest at runtime.
Bootc composes with systemd-sysext and confext for driver injection and per-fleet configuration without breaking the immutable base.
What is bootc and why it matters in 2026
Bootc, short for "bootable container", is a userspace agent and image format that lets a standard OCI container become the root filesystem of a Linux host. The image ships a full kernel, initramfs, systemd, and userland, and bootc install unpacks it onto a disk as an OSTree-backed deployment. From that point on, the host tracks a container image tag the way a Kubernetes node tracks a workload: bootc upgrade pulls the newer digest, stages it as a second deployment, and swaps roots on the next reboot. If that boot fails a health check, GRUB rolls back automatically.
So why does this matter in 2026? Red Hat has committed to image mode as the strategic direction for RHEL, replacing traditional package-mode installs for greenfield fleets, and Fedora ships a first-class fedora-bootc base you can extend with a Containerfile. Combined with sigstore-signed images and a hardened registry, the model collapses "OS build", "OS distribution", and "OS update" into one workflow that a supply-chain policy engine can reason about end to end. That pairs naturally with the Sigstore, SBOM, and SLSA supply chain controls most Linux shops already have in place.
How is bootc different from Podman and rpm-ostree?
Bootc, Podman, and rpm-ostree occupy adjacent slots but solve very different problems. Podman runs containers as workloads inside a Linux host. rpm-ostree manages a set of OS commits that a host boots into. Bootc is the newer glue: it uses OSTree under the hood but treats the source of truth as an OCI image in a registry, not as an rpm-ostree commit produced by a compose server. In practice, you use Podman (or Docker, or BuildKit) to build a bootc image, and you use bootc to install and upgrade a host from that image.
Dimension
bootc
rpm-ostree
Podman (workload)
Unit of deployment
OCI image with kernel
OSTree commit
OCI image without kernel
Build tool
Any OCI builder (Podman, buildah, BuildKit)
rpm-ostree compose
Any OCI builder
Distribution
Container registry
OSTree remote (HTTP)
Container registry
Root filesystem
Immutable, overlayed
Immutable, overlayed
N/A (host is separate)
Rollback
Automatic on failed boot
Manual or scripted
N/A
Signature enforcement
cosign / policy.json at pull
OSTree GPG signatures
cosign / policy.json at run
Target
Physical, VM, cloud instance
Same
Container on host
The important shift is that bootc removes the "compose server" middle tier. Any registry that speaks the OCI distribution spec (Harbor, Quay, GHCR, ECR, or a private Zot instance behind mTLS) becomes a valid delivery channel for your OS, and the same admission controls you already apply to workload images apply to the host image too. Under the hood, bootc still uses OSTree for atomic filesystem swaps and deduplicated storage, so most of the operational muscle memory from CoreOS and Silverblue transfers directly.
Building your first bootc image with a Containerfile
A bootc image is just a container image that starts FROM a base with a kernel, systemd, and the bootc tooling embedded. For Fedora 41 the base is quay.io/fedora/fedora-bootc:41; for RHEL 10 you pull registry.redhat.io/rhel10/rhel-bootc:10.0 after subscription. Everything else follows normal container discipline: layers cached by SHA, reproducible with pinned digests, buildable in CI.
# Containerfile: a minimal hardened web edge node
FROM quay.io/fedora/fedora-bootc:41
# Trim what the base image ships that we do not need
RUN dnf -y remove \
NetworkManager-tui \
cockpit \
firewalld \
&& dnf clean all
# Install the workload and hardening tooling
RUN dnf -y install \
nginx-mainline \
nftables \
systemd-resolved \
policycoreutils-python-utils \
&& dnf clean all
# Ship configuration as part of the image, not as post-install state
COPY etc/nginx/ /etc/nginx/
COPY etc/nftables/edge.nft /etc/nftables/edge.nft
COPY etc/systemd/system/ /etc/systemd/system/
# Enable services at build time
RUN systemctl enable nginx.service nftables.service systemd-resolved.service
# Force SELinux enforcing; refuse to boot in permissive
RUN sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config
# Lint the tree so a broken image never leaves CI
RUN bootc container lint
Two lines are worth flagging. bootc container lint catches classic mistakes (writable directories left in /opt, missing /boot entries, dangling symlinks) before the image ever hits a host. And copying config into the image rather than templating it at first boot means the same digest you signed is the digest that runs; a fleet-wide diff of /etc now equals "someone touched a running box", which is a much stronger detection primitive than staring at cloud-init logs.
A bootc container image on its own isn't a bootable disk. To turn it into a QCOW2, AMI, ISO, or raw image you invoke bootc-image-builder, which is itself a container that reads a config, pulls your image, and writes out installable media. This is the piece that replaces older workflows like osbuild-composer for the image-mode use case.
# config.toml: declarative disk layout with LUKS on root
[[customizations.filesystem]]
mountpoint = "/"
minsize = "20 GiB"
[[customizations.disk.partitions]]
type = "lvm"
name = "system"
[[customizations.disk.partitions.logical_volumes]]
name = "root"
minsize = "18 GiB"
fs_type = "xfs"
mountpoint = "/"
[customizations.kernel]
append = "console=ttyS0 audit=1 audit_backlog_limit=8192 lockdown=confidentiality"
[customizations.locale]
languages = ["en_US.UTF-8"]
[[customizations.user]]
name = "opsadmin"
key = "ssh-ed25519 AAAA... felix@laptop"
groups = ["wheel"]
Notice the kernel arguments in the config: enabling audit=1, a decent audit_backlog_limit, and lockdown=confidentiality at image-build time bakes hardening into every host that ever comes from this pipeline. No drift, no forgotten Ansible playbook. For the audit rules themselves, this pairs well with the practices in the auditd deep dive on rules, ausearch, and SIEM integration.
Deploying, upgrading, and rolling back
Once an image is on a host, bootc replaces most of what dnf used to do. The lifecycle is deliberately narrow: install once, upgrade to a new digest, roll back if something breaks. Everything else is either a workload (a container, running under Podman or systemd) or persistent data (which lives in /var).
# Check where the running system points
bootc status
# Pin to a specific tag or digest so upgrades are deterministic
bootc switch quay.io/example/edge-node:2026.09.07
# Stage the next deployment; nothing changes on the running root
bootc upgrade --apply=false
# When you are ready, reboot into the staged deployment
bootc upgrade --apply
# Something went wrong, flip back to the previous deployment
bootc rollback
For fleet-scale operation, tie bootc upgrade to a maintenance window with a systemd timer, and use bootc status --json to feed a dashboard that shows every host's current and staged image digests. Because the digest is what identifies the OS, an incident like "which of my 400 nodes is running the vulnerable build" becomes a one-line query against your fleet inventory instead of a scan across RPM databases.
Signing bootc images and enforcing verification at boot
The threat that image mode most cleanly kills is "attacker publishes a poisoned upgrade". Because the OS is a single OCI artefact, you can sign it with cosign's keyless signing flow during your CI build, and force bootc to refuse to pull an unsigned image at the host. That refusal happens before anything from the new image touches disk.
Sign at build time in your pipeline.
# In CI, after `podman push`
cosign sign --yes \
--oidc-issuer=https://token.actions.githubusercontent.com \
quay.io/example/edge-node:2026.09.07
# Attach a SBOM and provenance while we are here
cosign attest --yes \
--predicate sbom.spdx.json \
--type spdxjson \
quay.io/example/edge-node:2026.09.07
Then enforce on the host by dropping a signature policy in /etc/containers/policy.json. Bootc respects the same policy the container runtime does, which means one policy file governs both your workloads and your OS.
With that in place, a bootc upgrade that pulls an image signed by anything other than your CI workflow identity fails at the network boundary. Combine it with a policy engine like Kyverno or a Sigstore verifier at the registry, and you get defence-in-depth without inventing new tooling. Honestly, this is the part of the story I care about most: once the image is signed and the host will only accept your specific workflow identity, "someone typoed a registry URL" stops being a way to lose a fleet.
An attacker's view: what immutability actually blocks
I break into servers for a living, so let me be specific about which offensive plays image mode actually blocks and which ones it doesn't. The wins are real, but the marketing sometimes oversells.
What breaks for the attacker
Persistent on-disk implants outside /var and /etc. The root filesystem is a read-only overlay on an OSTree deployment. Dropping a rootkit in /usr/lib/systemd/system/ or replacing /usr/bin/sshd does not survive the next upgrade, because the deployment root is swapped, not patched.
Silent package tampering. There is no dnf install pathway on a running host worth attacking. If the attacker manages to add a package with rpm-ostree install, it produces a new deployment that shows up plainly in bootc status.
Long-lived config drift. Because /etc is a three-way merge against the image's /etc, any file the attacker touches is diffable against a signed base with ostree admin config-diff.
Compromised update servers. With sigstore policy enforced, a hijacked registry mirror cannot serve an unsigned or wrong-identity image; the host refuses the pull.
What does not break
Anything living in /var. Databases, application data, container volumes, and cron-installed persistence in /var/spool/cron all survive a rebase. Treat /var as the compromise-recovery boundary.
Memory-resident malware. An in-kernel eBPF implant or a userspace process injected via ptrace is unaffected until reboot; pair image mode with eBPF-aware runtime detection (see the Falco vs Tetragon eBPF runtime security comparison for options).
Credential theft from running workloads. If the attacker gets root on a live container, they can still exfiltrate secrets from /proc, kernel keyrings, or the workload's own memory. Immutability protects the OS, not the workload.
SSH key persistence. Authorized keys in /root/.ssh/authorized_keys live in /var-backed /root, so backdoored keys survive upgrades. Ship keys in the image and disable password authentication at build time.
The net-net: bootc raises the floor on host integrity dramatically, and it makes forensics and rollback trivial. It doesn't remove the need for kernel-level detection or workload hardening. That layer still matters, and technologies like immutable Kubernetes nodes with Talos, Bottlerocket, and Flatcar apply the same design idea to the container control plane.
Extending bootc with systemd-sysext and confext
The obvious objection to image mode is that fleet variance is real. Your GPU nodes need NVIDIA drivers your build farm nodes do not, and your EU region nodes have different TLS trust anchors than your APAC region nodes. Rebuilding a variant image per permutation is possible, but painful.
So, the answer in 2026 is systemd-sysext for binaries and confext for configuration. Both are overlays that systemd merges into /usr and /etc at boot from images stored in /var/lib/extensions and /var/lib/confexts. Because they're transient overlays, they don't violate the immutability of the OSTree root, and they can themselves be signed OCI images pulled by systemd-sysupdate.
# On a GPU node, drop a signed sysext image that adds the CUDA userland
sudo mkdir -p /var/lib/extensions
sudo cp cuda-13.0.raw /var/lib/extensions/
# Merge extensions into the live tree
sudo systemd-sysext refresh
# Verify what got layered in
systemd-sysext status
This pattern gives you a small, cachable base image and a matrix of per-fleet extensions, each individually signed and versioned. From an attacker's perspective, tampering with an extension still shows up in systemd-sysext status and can be verified against a known digest. (In my last on-call rotation I ran this exact setup for a small GPU pool, and the sanity of "one base image, one sysext per driver family" made rollbacks a two-command exercise instead of a fire drill.)
Bootc vs Fedora CoreOS and Silverblue
Fedora CoreOS (FCOS) and Fedora Silverblue predate bootc and use rpm-ostree with an Ignition or Anaconda first-boot config. They're excellent and still supported, but they can't be built with a plain Containerfile, they need a compose server to produce updates, and their update channel is an OSTree remote instead of an OCI registry. For 2026 the practical decision tree is: if you're starting fresh on servers, use bootc. If you already run FCOS and it's working, there is a supported rpm-ostree rebase path to a bootc image when you want to switch, and no urgent reason to migrate mid-cycle.
Silverblue is a workstation-focused variant and is less relevant for servers, but the same shift is happening there: Fedora is publishing bootc-shaped desktop images that let developers use the same build system for their laptop OS as for their production nodes. Red Hat's image mode for RHEL 10 documentation covers the enterprise workflow, including subscription attach and Insights integration.
Frequently Asked Questions
Is bootc production ready in 2026?
Yes. Red Hat's image mode for RHEL 10 is generally available under a full support subscription, Fedora bootc is stable and shipped in Fedora 41, and CentOS Stream provides community-supported bootc base images. Several public references, including edge and telco deployments, have been running bootc in production since 2025.
Can I use Docker to build a bootc image?
Yes. Any OCI-compliant builder works, including Docker, Podman, buildah, BuildKit, and Kaniko. The image only needs a bootc-capable base (fedora-bootc, centos-bootc, or rhel-bootc) and to pass bootc container lint. Distribution is via any OCI registry.
How do I roll back a bootc upgrade?
Run bootc rollback and reboot; the previous OSTree deployment is still on disk and GRUB will boot into it. If the failed boot triggers the greenboot health check, rollback happens automatically without operator intervention.
Does bootc work on ARM64 and cloud instances?
Yes. Bootc base images are published as multi-arch manifests for x86_64 and aarch64, and bootc-image-builder can output QCOW2, AMI, VHD, ISO, and raw disk formats suitable for AWS, Azure, GCP, and bare-metal or VM installs.
What happens to files in /etc when I upgrade a bootc image?
OSTree performs a three-way merge between the previous image's /etc, the current running /etc, and the new image's /etc. Local edits are preserved when they don't conflict with the new image; conflicts show up in ostree admin config-diff and are logged on boot.
Podman Quadlets turn rootless containers into first-class systemd services. Learn install, hardening, auto-updates, and troubleshooting on Linux in 2026.
Sigma turns Linux auditd, journald, sshd, and sudo events into portable YAML detections that compile to any SIEM. Learn pySigma, sigma-cli, Zircolite, and CI patterns for detection-as-code in 2026.
Install Zeek 7.x on Linux, tune AF_PACKET for line-rate capture, write your first detection script, use JA4 TLS fingerprints, and stitch Zeek into a SIEM for real threat hunting.