Preface
On the Universal Blue Discourse, I saw this very simple guide to creating your own bootc image that I wanted to share: Locally built, automatically updating custom bootc image - General - Universal Blue
Notably, this does not rely on something like Github Actions to build your image. So it’s more private, not reliant on the whims of Microsoft, and likely faster.
Warning
Warning: this is unofficial and you should only do this if you are aware of the risks.
Before doing anything, it’s a good idea to pin your existing version.
# if this fails, try 1 instead
sudo ostree admin pin 0
My version of the guide
To start, create a containerfile. Here’s an example of one based on mine.
# This is located at /etc/system-image - DO NOT INCLUDE THIS LINE
FROM quay.io/fedora/fedora-silverblue:43
RUN --mount=type=cache,destination=/var/cache/libdnf5 \
--mount=type=cache,destination=/var/lib/dnf5 \
--mount=type=tmpfs,destination=/var/log \
<<EOF
# bash safety options
set -euox pipefail
# remove packages
dnf5 remove -y gnome-software
# enable repos
dnf5 copr enable -y scottames/ghostty
# install packages
dnf5 install -y fastfetch ghostty zsh zsh-autosuggestions zsh-syntax-highlighting
# dnf cleanup
dnf5 clean all
EOF
RUN bootc container lint
Now, we create a systemd service to build that containerfile into an image.
# This is located at /etc/containers/systemd/system.build - DO NOT INCLUDE THIS LINE
[Build]
Arch=amd64
ImageTag=localhost/system-image
Pull=newer
SetWorkingDirectory=/etc/system-image
PodmanArgs=--squash
[Service]
ExecStartPost=/usr/bin/bootc switch --quiet --transport=containers-storage localhost/system-image:latest
ExecStartPost=/usr/bin/bootc update --quiet
Nice=0
We will also want a timer so that systemd will automatically build new images.
# This is located at /etc/systemd/system/system-build.timer - DO NOT INCLUDE THIS LINE
[Unit]
Description=Daily automatic builds for custom bootc image
[Timer]
OnCalendar=daily
OnBootSec=15min
[Install]
WantedBy=timers.target
Now, run the following command so systemd finds these files.
sudo systemctl daemon-reload
You can build and switch to the image by running
sudo systemctl start build system-build.service
You can watch the status of the build by running
sudo systemctl status system-build.service
And enable the timer for it by running
sudo systemctl enable --now system-build.timer
For my convenience, I store these 3 files in the same directory in my home. I then use this script to copy them to their proper places (works on a new installs and updates existing installs).
#!/bin/bash
# bash safety options
# -e exits on failure
# -u exits on unknown variables
# -o pipefail exits on failed pipe
set -euox pipefail
# regardless pwd when running, cd into this script's directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# move Containerfile to its destination
sudo mkdir -p /etc/system-image
sudo cp "$SCRIPT_DIR/Containerfile" /etc/system-image/
# move system.build to its destination
sudo mkdir -p /etc/containers/systemd
sudo cp "$SCRIPT_DIR/system.build" /etc/containers/systemd/
# move system-build.timer to its destination
sudo mkdir -p /etc/systemd/system
sudo cp "$SCRIPT_DIR/system-build.timer" /etc/systemd/system/
# run daemon-reload so systemd creates system-build.service
sudo systemctl daemon-reload
# enable and start the timer schedule
sudo systemctl enable --now system-build.timer
# trigger the build service to run immediately
sudo systemctl start system-build.service