Custom image for Laptops of an adult education centre

Hi!

I’m a teacher in an adult education centre. Fortunately we are switching our laptops, that are used in the lessons, to Linux. So I have to install them.

I decided to take bluefin:gts. (Firstly I wanted to install bluefin:lts, but I tested it in a VM and recognized, that it’s not production-ready yet.)

I want to create a custom image, because I want to manage them as central and easy as possible.

My question is: can I create a private repo for it? I don’t want to ship all components publicly. (For example: Maybe I have to install a printer driver as rpm in the image. I think in a public repo it would be illegal…)

And if I can, how? What are the differences compared to the public method?

Thanks in advance!

This would require a few things:

  • A private git repository to host the build scripts
  • A private OCI image registry to host the images
  • CI for building the former to produce the latter
  • Login credentials for the private image registry, possibly baked into the image

Github can provide the first three, although there are limits to what you can do for free. If you prefer to self-host, take a look at Forgejo or Gitea; they both have private package registries and CI tooling that is largely (but not completely) compatible with GitHub Actions.

As for the last part, you’ll want to configure bootc on every system with login credentials for the registry. Make sure to use a pull token that has as few permissions as possible. Ideally it shouldn’t be able to do anything more than read images from the registry.

(Also, as a CI best practices note, make sure you aren’t committing your pull token directly in the repo. Most CI systems have a means to store secrets, be sure to keep it there instead.)

1 Like

Although I feel compelled to note that it’s not generally a good idea to ship credentials in container images. This is a bit of a special case because you can’t update the system without credentials, and depending on how concerned you are about access to the registry, it might be fine, depending on your risk profile – just know that anyone who has access to a system running with your image on it may have the ability to exfiltrate the token and pull your images elsewhere.

The bootc secrets page I linked in my previous post has some strategies to work around this. The use of a token server to bootstrap the login seems interesting, although that’s more infrastructure you’ll have to create and maintain. Depending on how large a fleet you need to maintain, provisioning the secrets by hand might not be a bad solution either.

I’m in a similar situation to you but I am doing a little bit of management outside of the image and keeping the image free of private information. I’m using OpenVox Automation Framework to manage a secret, some mounts, printers and additional flatpaks for specific labs. I don’t think it would be good for layering in a package after the fact but you might setup your auth.json with it, maybe?

Of course what works for me might not work for you. In any case here is my image if you would like to take a look GitHub - jorussell1/ptschoolslinux: The blue build version

I always try if I can choose the most easy solution. IT is already complex enough :wink:

It is possible to install a rpm directly from a url. So if the printer package is hosted external by a supplier use that external source in your build pipeline.

Another option is to host the images in your internal network. And the images will update only when the laptops are connected in your LAN. So you don’t need any credentials in your build.

Or maybe tailscale is an option. Create a tailscale network and use the tailscale name resolution to contact your private git.

Extra perk; You can remotely manage the devices with SSH.

Thank you very much for your responses!

I have an idea: I will make a public repo as shown in the instructions. But I will make a gocryptfs-mount for all non-public stuff. The encrypted part will be in the os-image and /etc/fstab will be configured to mount it.

The key will be in the home-folder of root. I will install Silverblue on the first laptop and put the key in the right folder. So after rebasing it will work on first reboot already.

That maybe isn’t the right solution for a printer driver (I hope I won’t need any) but I can easily distribute things like

  • Startup-Scripts even with secrets in it
  • Wallpaper
  • A file with all gnome settings to load with dconf
  • Flatpak user data with optimum configuration of every used app
  • Appimages
  • etc.

Thanks all for this, it’s really interesting reading about these use cases and different approaches.

Why gocryptfs? It would probably be more performant to use a LUKS volume loop-mounted from a raw file.

Something to this effect:

fallocate -l 32GiB encrypted_disk.img # or whatever size you need
sudo losetup /dev/loop0 encrypted_disk.img
sudo cryptsetup luksFormat /dev/loop0 [keyfile]
sudo cryptsetup open /dev/loop0 encrypted_disk
sudo mkfs.ext4 /dev/mapper/encrypted_disk # or whatever filesystem you want to use
sudo mount /dev/mapper/encrypted_disk /mnt
# start copying files into `/mnt`

In a deployment scenario, you can use /etc/crypttab and /etc/fstab to automount the disk on boot. Bonus points if you set the ro mount option in fstab for the decrypted disk (we are all about image-based operating systems here, after all :slightly_smiling_face:).

Another thing worth noting here – and IANAL, so take this advice with a a grain of salt – but if the concern you had about hosting a private image is related to your legal ability to redistribute software, simply encrypting the file where the software is stored may not be enough to protect you from liability. So, I’d still be cautious of what you expose publicly in that regard.

Another thing worth noting: to my understanding there is a general idea when designing private communications systems that any encrypted files/communications that are transmitted over untrusted networks will eventually be decrypted. How long that is depends on the strength of the encryption and the key (it could be thousands or millions of years if done correctly), but just know that encrypting something that is otherwise private by itself doesn’t guarantee perfect privacy (although, frankly, neither does using private infrastructure. Best practice would be to combine both!).

Just make sure you’re keeping that in mind when you’re designing your solution.

Thanks for reply!

Because gocryptfs doesn’t need a defined size in advance.

As I wrote, the things I will put in this secret place is not that private and also not illegal. But I don’t want to distribute them publicly. For example a password in a script should not be public. Or some user data of a flatpak, because you never know, what a user put in there. But if the technology comes to a point where AES256 can be decrypted in short time, the password won’t exist anymore or can be broken also.

Understood about the latter points.

To the point about gocryptfs: what’s the advantage of having an unfixed size on the filesystem? Since this is a part of the distribution, the contents aren’t changing over the lifespan of a single image, so there’s no reason to think an individual version of your encrypted volume would change on the user side. Sure, if you need to change what’s in the volume on the upstream side, you’ll likely need to change the size of the file in your build script, but to me that is the better option than having all of my users deal with the FUSE performance overhead.

You mention user data being stored in the encrypted volume, presumably this is just seed data? If your expectation is that mutable user state would be stored in this image, it would probably be better placed elsewhere on the system.

I want to store startup-scripts, wallpapers, etc. in the encrypted part of the image. Maybe I will configure all apps as I want (e.g. optimal settings in Brave) and copy the ~/.var/app folder into this space. At certain time i can add a command to a startup script to delete the ~/.var/app folder and replace it with the template out of the encrypted part of the image. So I can make undone changes of this optimal settings when a course is over.

And when I want to alter some setting and copy the folder again and forget to delete some user-data it could accidentally get to the folder. That’s the reason I don’t want it to be public.

I forked the image-template yesterday: GitHub - wepantech/edu-os: Universal Blue OS variant for private use.

I decided to do the encrypted part with LUKS, many thanks for the explaination and the notice about performance!

Sadly the push to GHCR fails out of some reason, although the build process was successful. The output is that:



Run redhat-actions/push-to-registry@5ed88d269cf581ea9ef6dd6806d01562096bee9c




  with:


  registry: ghcr.io/wepantech


  image: edu-os


  tags: latest latest.20260126 20260126


  username: wepantech


  password: ***


  tls-verify: true


env:


  IMAGE_DESC: My Customized Universal Blue Image


  IMAGE_KEYWORDS: bootc,ublue,universal-blue


  IMAGE_LOGO_URL: https://avatars.githubusercontent.com/u/120078124?s=200&v=4


  IMAGE_NAME: edu-os


  IMAGE_REGISTRY: ghcr.io/wepantech


  DEFAULT_TAG: latest


  DOCKER_METADATA_OUTPUT_VERSION: latest


  DOCKER_METADATA_OUTPUT_TAGS: latest latest.20260126 20260126


  DOCKER_METADATA_OUTPUT_TAG_NAMES: latest latest.20260126 20260126


  DOCKER_METADATA_OUTPUT_LABELS: containers.bootc=1


io.artifacthub.package.deprecated=false


io.artifacthub.package.keywords=bootc,ublue,universal-blue


io.artifacthub.package.license=Apache-2.0


io.artifacthub.package.logo-url=https://avatars.githubusercontent.com/u/120078124?s=200&v=4


io.artifacthub.package.prerelease=false


io.artifacthub.package.readme-url=https://raw.githubusercontent.com/wepantech/edu-os/fd845a8d8049792b2ca41cc9ce717fb16b72ad6b/README.md


org.opencontainers.image.created=2026-01-26T00:46:28Z


org.opencontainers.image.description=My Customized Universal Blue Image


org.opencontainers.image.documentation=https://raw.githubusercontent.com/wepantech/edu-os/fd845a8d8049792b2ca41cc9ce717fb16b72ad6b/README.md


org.opencontainers.image.licenses=Apache-2.0


org.opencontainers.image.revision=fd845a8d8049792b2ca41cc9ce717fb16b72ad6b


org.opencontainers.image.source=https://github.com/wepantech/edu-os/blob/fd845a8d8049792b2ca41cc9ce717fb16b72ad6b/Containerfile


org.opencontainers.image.title=edu-os


org.opencontainers.image.url=https://github.com/wepantech/edu-os/tree/fd845a8d8049792b2ca41cc9ce717fb16b72ad6b


org.opencontainers.image.vendor=wepantech


org.opencontainers.image.version=latest.20260126


  DOCKER_METADATA_OUTPUT_ANNOTATIONS: manifest:org.opencontainers.image.created=2026-01-26T00:46:28.814Z manifest:org.opencontainers.image.description=Universal Blue OS variant for private use. manifest:org.opencontainers.image.licenses=Apache-2.0 manifest:org.opencontainers.image.revision=fd845a8d8049792b2ca41cc9ce717fb16b72ad6b manifest:org.opencontainers.image.source=https://github.com/wepantech/edu-os manifest:org.opencontainers.image.title=edu-os manifest:org.opencontainers.image.url=https://github.com/wepantech/edu-os manifest:org.opencontainers.image.version=latest


  DOCKER_METADATA_OUTPUT_JSON: {"tags":["latest","latest.20260126","20260126"],"tag-names":["latest","latest.20260126","20260126"],"labels":{"containers.bootc":"1","io.artifacthub.package.deprecated":"false","io.artifacthub.package.keywords":"bootc,ublue,universal-blue","io.artifacthub.package.license":"Apache-2.0","io.artifacthub.package.logo-url":"https://avatars.githubusercontent.com/u/120078124?s=200&v=4","io.artifacthub.package.prerelease":"false","io.artifacthub.package.readme-url":"https://raw.githubusercontent.com/wepantech/edu-os/fd845a8d8049792b2ca41cc9ce717fb16b72ad6b/README.md","org.opencontainers.image.created":"2026-01-26T00:46:28Z","org.opencontainers.image.description":"My Customized Universal Blue Image","org.opencontainers.image.documentation":"https://raw.githubusercontent.com/wepantech/edu-os/fd845a8d8049792b2ca41cc9ce717fb16b72ad6b/README.md","org.opencontainers.image.licenses":"Apache-2.0","org.opencontainers.image.revision":"fd845a8d8049792b2ca41cc9ce717fb16b72ad6b","org.opencontainers.image.source":"https://github.com/wepantech/edu-os/blob/fd845a8d8049792b2ca41cc9ce717fb16b72ad6b/Containerfile","org.opencontainers.image.title":"edu-os","org.opencontainers.image.url":"https://github.com/wepantech/edu-os/tree/fd845a8d8049792b2ca41cc9ce717fb16b72ad6b","org.opencontainers.image.vendor":"wepantech","org.opencontainers.image.version":"latest.20260126"},"annotations":["manifest:org.opencontainers.image.created=2026-01-26T00:46:28.814Z","manifest:org.opencontainers.image.description=Universal Blue OS variant for private use.","manifest:org.opencontainers.image.licenses=Apache-2.0","manifest:org.opencontainers.image.revision=fd845a8d8049792b2ca41cc9ce717fb16b72ad6b","manifest:org.opencontainers.image.source=https://github.com/wepantech/edu-os","manifest:org.opencontainers.image.title=edu-os","manifest:org.opencontainers.image.url=https://github.com/wepantech/edu-os","manifest:org.opencontainers.image.version=latest"]}


  DOCKER_METADATA_OUTPUT_BAKE_FILE_TAGS: /home/runner/work/_temp/docker-actions-toolkit-xqwk9u/docker-metadata-action-bake-tags.json


  DOCKER_METADATA_OUTPUT_BAKE_FILE_LABELS: /home/runner/work/_temp/docker-actions-toolkit-xqwk9u/docker-metadata-action-bake-labels.json


  DOCKER_METADATA_OUTPUT_BAKE_FILE_ANNOTATIONS: /home/runner/work/_temp/docker-actions-toolkit-xqwk9u/docker-metadata-action-bake-annotations.json


  DOCKER_METADATA_OUTPUT_BAKE_FILE: /home/runner/work/_temp/docker-actions-toolkit-xqwk9u/docker-metadata-action-bake.json


  REGISTRY_USER: wepantech


  REGISTRY_PASSWORD: ***


Creating temporary Podman image storage for pulling from Docker daemon


Storage driver is not 'overlay', so not overriding storage configuration


Combining image name "edu-os" and registry "ghcr.io/wepantech" to form registry path "ghcr.io/wepantech/edu-os"


🔍 Checking if the given image is manifest or not.


/usr/bin/podman version




/usr/bin/podman version


Client:       Podman Engine


Version:      4.9.3


API Version:  4.9.3


Go Version:   go1.22.2


Built:        Thu Jan  1 00:00:00 1970


OS/Arch:      linux/amd64


/usr/bin/podman manifest exists edu-os:latest




/usr/bin/podman manifest exists edu-os:latest


Error: localhost/edu-os:latest: image is not a manifest list


/usr/bin/podman manifest exists edu-os:latest.20260126




/usr/bin/podman manifest exists edu-os:latest.20260126


Error: localhost/edu-os:latest.20260126: image is not a manifest list


/usr/bin/podman manifest exists edu-os:20260126




/usr/bin/podman manifest exists edu-os:20260126


Error: localhost/edu-os:20260126: image is not a manifest list


🔍 Checking if "edu-os:latest, edu-os:latest.20260126, edu-os:20260126" present in the local Podman image storage


/usr/bin/podman image exists edu-os:latest


/usr/bin/podman image exists edu-os:latest.20260126


/usr/bin/podman image exists edu-os:20260126


Tags "edu-os:latest, edu-os:latest.20260126, edu-os:20260126" found in Podman image storage


🔍 Checking if "edu-os:latest, edu-os:latest.20260126, edu-os:20260126" present in the local Docker image storage


/usr/bin/podman --root /tmp/podman-from-docker-kihBO0 pull docker-daemon:edu-os:latest




/usr/bin/podman --root /tmp/podman-from-docker-kihBO0 pull docker-daemon:edu-os:latest


Error: initializing source docker-daemon:edu-os:latest: loading image from docker engine: Error response from daemon: reference does not exist


/usr/bin/podman --root /tmp/podman-from-docker-kihBO0 pull docker-daemon:edu-os:latest.20260126




/usr/bin/podman --root /tmp/podman-from-docker-kihBO0 pull docker-daemon:edu-os:latest.20260126


Error: initializing source docker-daemon:edu-os:latest.20260126: loading image from docker engine: Error response from daemon: reference does not exist


/usr/bin/podman --root /tmp/podman-from-docker-kihBO0 pull docker-daemon:edu-os:20260126




/usr/bin/podman --root /tmp/podman-from-docker-kihBO0 pull docker-daemon:edu-os:20260126


Error: initializing source docker-daemon:edu-os:20260126: loading image from docker engine: Error response from daemon: reference does not exist


Tag "edu-os:latest" was found in the Podman image storage, but not in the Docker image storage. The image(s) will be pushed from Podman image storage.


⏳ Pushing "edu-os:latest, edu-os:latest.20260126, edu-os:20260126" to "ghcr.io/wepantech/edu-os:latest, ghcr.io/wepantech/edu-os:latest.20260126, ghcr.io/wepantech/edu-os:20260126" respectively as "wepantech"


/usr/bin/podman push --quiet --digestfile edu-os-latest_digest.txt edu-os:latest ghcr.io/wepantech/edu-os:latest --tls-verify=true --creds=wepantech:***


Error: writing blob: initiating layer upload to /v2/wepantech/edu-os/blobs/uploads/ in ghcr.io: denied: permission_denied: write_package


Removing temporary Podman image storage for pulling from Docker daemon


/usr/bin/podman --root /tmp/podman-from-docker-kihBO0 rmi -a -f


(node:3693) [DEP0147] DeprecationWarning: In future versions of Node.js, fs.rmdir(path, { recursive: true }) will be removed. Use fs.rm(path, { recursive: true }) instead


(Use `node --trace-deprecation ...` to show where the warning was created)


Error: podman exited with code 125


Error: writing blob: initiating layer upload to /v2/wepantech/edu-os/blobs/uploads/ in ghcr.io: denied: permission_denied: write_package

And the build of an ISO image fails too:

Run osbuild/bootc-image-builder-action@main


  with:


  builder-image: quay.io/centos-bootc/bootc-image-builder:latest


  config-file: ./disk_config/iso.toml


  image: ghcr.io/wepantech/edu-os:latest


  chown: 1001:1001


  types: anaconda-iso


  additional-args: --use-librepo=True


  tls-verify: true


env:


  IMAGE_NAME: edu-os


  IMAGE_REGISTRY: ghcr.io/wepantech


  DEFAULT_TAG: latest


  BIB_IMAGE: quay.io/centos-bootc/bootc-image-builder:latest


  DISK_TYPE: anaconda-iso


  USER_UID: 1001


  USER_GID: 1001


/usr/bin/sudo rm -rf /var/lib/containers/storage


/usr/bin/sudo mkdir -p /etc/containers


/usr/bin/sudo sh -c echo '[storage]


driver = "overlay"


runroot = "/run/containers/storage"


graphroot = "/var/lib/containers/storage"


' > /etc/containers/storage.conf.tmp


/usr/bin/sudo mv /etc/containers/storage.conf.tmp /etc/containers/storage.conf


Pulling required images


/usr/bin/sudo podman pull quay.io/centos-bootc/bootc-image-builder:latest


time="2026-01-26T01:05:49Z" level=warning msg="Error validating CNI config file /etc/cni/net.d/87-podman-bridge.conflist: [failed to find plugin \"bridge\" in path [/usr/local/libexec/cni /usr/libexec/cni /usr/local/lib/cni /usr/lib/cni /opt/cni/bin] failed to find plugin \"portmap\" in path [/usr/local/libexec/cni /usr/libexec/cni /usr/local/lib/cni /usr/lib/cni /opt/cni/bin] failed to find plugin \"firewall\" in path [/usr/local/libexec/cni /usr/libexec/cni /usr/local/lib/cni /usr/lib/cni /opt/cni/bin] failed to find plugin \"tuning\" in path [/usr/local/libexec/cni /usr/libexec/cni /usr/local/lib/cni /usr/lib/cni /opt/cni/bin]]"


Trying to pull quay.io/centos-bootc/bootc-image-builder:latest...


Getting image source signatures


Copying blob sha256:0b49b961bb519f5d23b5d6367e2b29869cce9095a97062fe48eb35249cf6cf8e


Copying blob sha256:8421f1f9477530774064e70a6bd4bfa99a5d8085b4019101e34b4b24615f6309


Copying config sha256:fe1fe57cef76f39cc0c0792c38c3ef91f1d0304131b303f77432f32d02bdff02


Writing manifest to image destination


fe1fe57cef76f39cc0c0792c38c3ef91f1d0304131b303f77432f32d02bdff02


/usr/bin/sudo podman pull ghcr.io/wepantech/edu-os:latest


Trying to pull ghcr.io/wepantech/edu-os:latest...


Getting image source signatures


Copying blob sha256:a7ca7e71d12d1ff19f9726ed6a151109a40becc996529a513328899c1adc2480


Copying blob sha256:2c00a24a570a385a6c28a8691fbcce1f359f22f20817fa50114ababd1b8b1d3f


Copying blob sha256:cefea3cd6eac08a5a2b1545b9c41f60aa13221ff655d46545ffbe60121ff27fc


Copying blob sha256:4e913f6a913dcb6a54f3f940ea7ac229e7c26bbf88909b287a68fc94e4c2e1ff


Copying blob sha256:52123c0cbb82f9be8196601eab471954bf4fe7887db21a6498b9c5ad35eefc2c


Copying blob sha256:584caadb07150cfd9d3f2bb62eefa74b3755fae3a67aaff764360c85e280d3a6


Copying blob sha256:58cc4715a372d3eb22c90962268cd22da6d1ee7084c1b5e85d4390ccab5fc87e


Copying blob sha256:79c3d36c8ecf64d28889c16d4a335995443580cb9e7133556f6d12f92958f1c0


Copying blob sha256:13c6d6fd891554307f78eeb7d29902b102dcd98e1df788eafcdf5190b701a2b0


Copying blob sha256:25d903f1801d46e2838e0f31a3d6a5bc99febe73f3776242b06188d1aedab306


Copying blob sha256:e47ae59dba421de02f3db7d2e2b363b3899a4fcacbf40a09ba760d01da272270


Copying blob sha256:25a09b2478564bfa8e791c792a66ffa520f0f2693bb1edf3ac92182f6c23ad0c


Copying blob sha256:44efb89bc09f903f68ae5adda06c0dd2f55b5e68b204067f1cc4545f2b720ee9


Copying blob sha256:2bbe7c8476cb689d357c4990fe8b05805efa556679edf15189434e5ff18aec58


Copying blob sha256:e50bee8cdef276f855612cc48739ec4e53d084c85496dc8385246a6ba29c5c2e


Copying blob sha256:2afc0a69ec7b80469aac3997a8e7593313b5b5a19ba40304e160c81e30607435


Copying blob sha256:3beec3eb3cdb023db264c9370d6a071449ee1ce9aeebb7719fa00afc3ccd0a92


Copying blob sha256:c3db7c6ef4da6be5ea1f343f6bcc0ba4ffcaa2d46fc395ecd286affe877daea2


Copying blob sha256:8ad4dddd10acecdce10313553a24f222eaba581f2c047e64be722fea47a42ece


Copying blob sha256:93794f5bc85fa766b7c6ce0dc4a48efd7ad9d298be34c3111e6822f8997abaa9


Copying blob sha256:d7eeb413f8f9a0c56d180ace4d24021ff4f33f56615450d2d87e1cb6663d6a27


Copying blob sha256:0882dbd3463355b08eccdb29004b4cce52d61574bcb38272d027287bc9f57d2f


Copying blob sha256:b1632253081e8cf535483ff0da442114d9587a90ee5456fa30021923d28021e5


Copying blob sha256:b679c688e83170a119a203987ff9e1b5e0edc41cdc5baaaf7bc8e181fe2e056d


Copying blob sha256:95287363030eb2fe06cb363d24c9489e0bebd91d1412113385b3fe0a99ead29e


Copying blob sha256:0289fbbbe2eeefa9b93da1513f7d9df8b4e19377fed683a3d6698aaf5f490c63


Copying blob sha256:ef299794b746582afa90d70916daa924429fbaf5607552acbc08d15aa67f67e0


Copying blob sha256:019fde2456464f84f79e162841a8ea54943528a75ae1f1d6a0d179f01052718c


Copying blob sha256:38ed2069c45379e2b6e853bcdf6f389c43b905309775a53c710f292bd7f10e27


Copying blob sha256:769ba1241a98ff7abd05698db5378af753d1117fa71023527db6bb43ae74bd5a


Copying blob sha256:3830967b82c9d5ea1cfd3e17d5766acad0215cb02a121d1d92fe5cbd857c340f


Copying blob sha256:b203161fc6a8c2b8212600ec29bbacdaa21094a4e1522af04dc4f467422046d6


Copying blob sha256:0a53209a2c1ff206cc0b2f80b041038b95c8ecdebf077f57e90894837acc3f06


Copying blob sha256:ba4062c509f4402bbf5a10f18eb7f27cea890e88bda2ba3f47fc8e7ee769955c


Copying blob sha256:2f660d936caacd9a8a0957bace9005e739833214afc9e139028ca8035d2bdf2c


Copying blob sha256:6be8e59bcddd94f308ee7f89cb832ecc32f346d7ecfd9f970bfa16fc6606628f


Copying blob sha256:b9d4073cfb1778dd847fa0457a6be72449393d88e3091dd38481753ffe9ce317


Copying blob sha256:f55ad035a55ea8c37392870b9529eaadac7786a7d04a8d2236e7181c20ab5c96


Copying blob sha256:04ef6e05cbe3d03ebb5acb87f20de301feac87fe1700ea7a909fbdcc22782310


Copying blob sha256:cb9c26585aa1d4cfa0eb49905a7ce48b46b95ecfa6442a073ddada79578e8603


Copying blob sha256:4ebccc27282273c4f7d35d8611c44f459ed8a1ee8042a6318d77fc65b2702466


Copying blob sha256:339a6a0bbca207089efa2fd9bf9d400303434d11c58fecf1989bbf55209b678d


Copying blob sha256:26c5b07e5023974f024a1153ecd3b50f63d954bae2560cab63cb10ebf7c90361


Copying blob sha256:cafc7b8114b497b5e46468bddd1d94f218259d15377608a5b095ca467582ce94


Copying blob sha256:12c6d604d711e05bc4c9b4b5217b4e63f1ac36fb2af3a05fd5518255d172eb2e


Copying blob sha256:09de6313856245e364ec9182e2ffaafda0aa46749340af21bbe605eb289edb9b


Copying blob sha256:33fc265f1a0ead89a397e30224d2a48b48933b6f5e7d02cb9b5e035915724d7d


Copying blob sha256:d1eac6cd96700f79cf7a6af70bb685f404dba7697e317fc161cedb3213f5de55


Copying blob sha256:82d102de675ed81d19e75ccbf2a7f570f8e7175572c257b16eb81fe8ee43c61d


Copying blob sha256:0e4be1a7706aef4fb40db8b50c9174ffa98e5eb77430161a6b913b8d39681ec0


Copying blob sha256:e180137663d0922bdd1197723ad6d0deb3211a37d5c4f6fde12743639a569804


Copying blob sha256:e93d017dbb624cad4b217cf80e49b5c3fb3d6657604ef01cfc4c0093e4d779bc


Copying blob sha256:689fcce49498bf311ff3ad107ce4631c46132e7c6d41736a2efd1d3bc648218e


Copying blob sha256:cc18bb25f9b4fec4e264abff81a9fe2c3983d33123aede4af5ae19c0a965ac72


Copying blob sha256:3a416f05e656cfecfcf1c32e6885aecc0764a726da9d3a9d2c2a9863e9422d5a


Copying blob sha256:b24edc6713e62d4f42095929420491b7734f24ef3d37ab25c48d1a301289c105


Copying blob sha256:10b1b696718a327b8a2581f1399f19d725bae221a364083fa3f72c47c7ae1b95


Copying blob sha256:b81b2285e98fc9156e517e7374ad322fad9738131f810f161f0bd48248371805


Copying blob sha256:d9c0af72c6ed34e51f45cfa561a5e776fc3a20f938f7f4187f26e5ca1015c4fe


Copying blob sha256:89c3e7d01ec5560783177792803d88034e1cfbaf109425a6eda3007163c7d75b


Copying blob sha256:3542b0caf069b91fbf25455168534094df933a621c6c344d14d3ac33cbe44e3c


Copying blob sha256:6dbfda24bbbf2a76ed4792572a1659606fe43df23e9ba295e7af14da7628c604


Copying blob sha256:ba1668f9923b4ef206a17e5cc2b2d2220bcb1931fa8d636caec56ceb8683b440


Copying blob sha256:017396ce75261aec71bd36efe0d9b8362453f3147fbd889cf19d845cf4078115


Copying blob sha256:c8efcd5b2431ae1cb9bf86da372515e5ecb83473ca5352e168a28393210c24a7


Copying blob sha256:49a08729fde948a3a21c3fb929f133dc5765c43b63ad53272545d9d0c8c905a3


Copying blob sha256:495bc47f45ad9fd2527f7e1ba831f1663c03ed78453feed455e69e58ddbc7df7


Copying blob sha256:943304e9332068d75337b6025dcb2f4bdab8c0af3fca9a5dcf37881fc9afe5b9


Copying blob sha256:2d7857a255e46e4ad503370dd970a35a79c3ed6fe1a8bf58388ad6e80a88f3e0


Copying blob sha256:a56ebcdc4556e3e5b3ebbcab4f96d2be7a9edfaa6b7286d26ac33b5fe8e4ee04


Copying blob sha256:6928bae819e792526010653084e63a3faabab22428707f3372482ec15cc55803


Copying blob sha256:dba16e336c50470f8cb5c24b37cf72f161b1bb0ca36620567d63ebc458a9add9


Copying blob sha256:ad312c5c40ccd18a3c639cc139211f3c4284e568b69b2e748027cee057986fe0


Copying blob sha256:5d34979223330be17cb4899d009fdf43780c17cb84bfca0fa04325825c2331d9


Copying config sha256:44fee9e7f68f0573040a39837fa52bf1a6da69db89ca5e1dfcbb0f4aa46d54be


Writing manifest to image destination


44fee9e7f68f0573040a39837fa52bf1a6da69db89ca5e1dfcbb0f4aa46d54be


/usr/bin/sudo mkdir -p ./output


Building artifact(s)


/usr/bin/sudo podman run --rm --privileged --security-opt label=type:unconfined_t --volume /var/lib/containers/storage:/var/lib/containers/storage --volume ./output:/output --volume ./disk_config/iso.toml:/config.toml:ro quay.io/centos-bootc/bootc-image-builder:latest build --output /output --chown 1001:1001 --use-librepo=True --type anaconda-iso ghcr.io/wepantech/edu-os:latest


Error: lstat disk_config/iso.toml: no such file or directory


Error: Build process failed: The process '/usr/bin/sudo' failed with exit code 125

And the build of qcow2 fails too:



Run osbuild/bootc-image-builder-action@main




  with:


  builder-image: quay.io/centos-bootc/bootc-image-builder:latest


  config-file: ./disk_config/disk.toml


  image: ghcr.io/wepantech/edu-os:latest


  chown: 1001:1001


  types: qcow2


  additional-args: --use-librepo=True


  tls-verify: true


env:


  IMAGE_NAME: edu-os


  IMAGE_REGISTRY: ghcr.io/wepantech


  DEFAULT_TAG: latest


  BIB_IMAGE: quay.io/centos-bootc/bootc-image-builder:latest


  DISK_TYPE: qcow2


  USER_UID: 1001


  USER_GID: 1001


/usr/bin/sudo rm -rf /var/lib/containers/storage


/usr/bin/sudo mkdir -p /etc/containers


/usr/bin/sudo sh -c echo '[storage]


driver = "overlay"


runroot = "/run/containers/storage"


graphroot = "/var/lib/containers/storage"


' > /etc/containers/storage.conf.tmp


/usr/bin/sudo mv /etc/containers/storage.conf.tmp /etc/containers/storage.conf


Pulling required images




/usr/bin/sudo podman pull quay.io/centos-bootc/bootc-image-builder:latest


time="2026-01-26T01:05:44Z" level=warning msg="Error validating CNI config file /etc/cni/net.d/87-podman-bridge.conflist: [failed to find plugin \"bridge\" in path [/usr/local/libexec/cni /usr/libexec/cni /usr/local/lib/cni /usr/lib/cni /opt/cni/bin] failed to find plugin \"portmap\" in path [/usr/local/libexec/cni /usr/libexec/cni /usr/local/lib/cni /usr/lib/cni /opt/cni/bin] failed to find plugin \"firewall\" in path [/usr/local/libexec/cni /usr/libexec/cni /usr/local/lib/cni /usr/lib/cni /opt/cni/bin] failed to find plugin \"tuning\" in path [/usr/local/libexec/cni /usr/libexec/cni /usr/local/lib/cni /usr/lib/cni /opt/cni/bin]]"


Trying to pull quay.io/centos-bootc/bootc-image-builder:latest...


Getting image source signatures


Copying blob sha256:0b49b961bb519f5d23b5d6367e2b29869cce9095a97062fe48eb35249cf6cf8e


Copying blob sha256:8421f1f9477530774064e70a6bd4bfa99a5d8085b4019101e34b4b24615f6309


Copying config sha256:fe1fe57cef76f39cc0c0792c38c3ef91f1d0304131b303f77432f32d02bdff02


Writing manifest to image destination


fe1fe57cef76f39cc0c0792c38c3ef91f1d0304131b303f77432f32d02bdff02


/usr/bin/sudo podman pull ghcr.io/wepantech/edu-os:latest


Trying to pull ghcr.io/wepantech/edu-os:latest...


Getting image source signatures


Copying blob sha256:cefea3cd6eac08a5a2b1545b9c41f60aa13221ff655d46545ffbe60121ff27fc


Copying blob sha256:584caadb07150cfd9d3f2bb62eefa74b3755fae3a67aaff764360c85e280d3a6


Copying blob sha256:52123c0cbb82f9be8196601eab471954bf4fe7887db21a6498b9c5ad35eefc2c


Copying blob sha256:a7ca7e71d12d1ff19f9726ed6a151109a40becc996529a513328899c1adc2480


Copying blob sha256:4e913f6a913dcb6a54f3f940ea7ac229e7c26bbf88909b287a68fc94e4c2e1ff


Copying blob sha256:2c00a24a570a385a6c28a8691fbcce1f359f22f20817fa50114ababd1b8b1d3f


Copying blob sha256:58cc4715a372d3eb22c90962268cd22da6d1ee7084c1b5e85d4390ccab5fc87e


Copying blob sha256:79c3d36c8ecf64d28889c16d4a335995443580cb9e7133556f6d12f92958f1c0


Copying blob sha256:13c6d6fd891554307f78eeb7d29902b102dcd98e1df788eafcdf5190b701a2b0


Copying blob sha256:25d903f1801d46e2838e0f31a3d6a5bc99febe73f3776242b06188d1aedab306


Copying blob sha256:e47ae59dba421de02f3db7d2e2b363b3899a4fcacbf40a09ba760d01da272270


Copying blob sha256:25a09b2478564bfa8e791c792a66ffa520f0f2693bb1edf3ac92182f6c23ad0c


Copying blob sha256:44efb89bc09f903f68ae5adda06c0dd2f55b5e68b204067f1cc4545f2b720ee9


Copying blob sha256:2bbe7c8476cb689d357c4990fe8b05805efa556679edf15189434e5ff18aec58


Copying blob sha256:e50bee8cdef276f855612cc48739ec4e53d084c85496dc8385246a6ba29c5c2e


Copying blob sha256:2afc0a69ec7b80469aac3997a8e7593313b5b5a19ba40304e160c81e30607435


Copying blob sha256:3beec3eb3cdb023db264c9370d6a071449ee1ce9aeebb7719fa00afc3ccd0a92


Copying blob sha256:c3db7c6ef4da6be5ea1f343f6bcc0ba4ffcaa2d46fc395ecd286affe877daea2


Copying blob sha256:8ad4dddd10acecdce10313553a24f222eaba581f2c047e64be722fea47a42ece


Copying blob sha256:93794f5bc85fa766b7c6ce0dc4a48efd7ad9d298be34c3111e6822f8997abaa9


Copying blob sha256:d7eeb413f8f9a0c56d180ace4d24021ff4f33f56615450d2d87e1cb6663d6a27


Copying blob sha256:0882dbd3463355b08eccdb29004b4cce52d61574bcb38272d027287bc9f57d2f


Copying blob sha256:b1632253081e8cf535483ff0da442114d9587a90ee5456fa30021923d28021e5


Copying blob sha256:b679c688e83170a119a203987ff9e1b5e0edc41cdc5baaaf7bc8e181fe2e056d


Copying blob sha256:95287363030eb2fe06cb363d24c9489e0bebd91d1412113385b3fe0a99ead29e


Copying blob sha256:0289fbbbe2eeefa9b93da1513f7d9df8b4e19377fed683a3d6698aaf5f490c63


Copying blob sha256:ef299794b746582afa90d70916daa924429fbaf5607552acbc08d15aa67f67e0


Copying blob sha256:019fde2456464f84f79e162841a8ea54943528a75ae1f1d6a0d179f01052718c


Copying blob sha256:38ed2069c45379e2b6e853bcdf6f389c43b905309775a53c710f292bd7f10e27


Copying blob sha256:769ba1241a98ff7abd05698db5378af753d1117fa71023527db6bb43ae74bd5a


Copying blob sha256:3830967b82c9d5ea1cfd3e17d5766acad0215cb02a121d1d92fe5cbd857c340f


Copying blob sha256:b203161fc6a8c2b8212600ec29bbacdaa21094a4e1522af04dc4f467422046d6


Copying blob sha256:0a53209a2c1ff206cc0b2f80b041038b95c8ecdebf077f57e90894837acc3f06


Copying blob sha256:ba4062c509f4402bbf5a10f18eb7f27cea890e88bda2ba3f47fc8e7ee769955c


Copying blob sha256:2f660d936caacd9a8a0957bace9005e739833214afc9e139028ca8035d2bdf2c


Copying blob sha256:6be8e59bcddd94f308ee7f89cb832ecc32f346d7ecfd9f970bfa16fc6606628f


Copying blob sha256:b9d4073cfb1778dd847fa0457a6be72449393d88e3091dd38481753ffe9ce317


Copying blob sha256:f55ad035a55ea8c37392870b9529eaadac7786a7d04a8d2236e7181c20ab5c96


Copying blob sha256:04ef6e05cbe3d03ebb5acb87f20de301feac87fe1700ea7a909fbdcc22782310


Copying blob sha256:cb9c26585aa1d4cfa0eb49905a7ce48b46b95ecfa6442a073ddada79578e8603


Copying blob sha256:4ebccc27282273c4f7d35d8611c44f459ed8a1ee8042a6318d77fc65b2702466


Copying blob sha256:339a6a0bbca207089efa2fd9bf9d400303434d11c58fecf1989bbf55209b678d


Copying blob sha256:26c5b07e5023974f024a1153ecd3b50f63d954bae2560cab63cb10ebf7c90361


Copying blob sha256:cafc7b8114b497b5e46468bddd1d94f218259d15377608a5b095ca467582ce94


Copying blob sha256:12c6d604d711e05bc4c9b4b5217b4e63f1ac36fb2af3a05fd5518255d172eb2e


Copying blob sha256:09de6313856245e364ec9182e2ffaafda0aa46749340af21bbe605eb289edb9b


Copying blob sha256:33fc265f1a0ead89a397e30224d2a48b48933b6f5e7d02cb9b5e035915724d7d


Copying blob sha256:d1eac6cd96700f79cf7a6af70bb685f404dba7697e317fc161cedb3213f5de55


Copying blob sha256:82d102de675ed81d19e75ccbf2a7f570f8e7175572c257b16eb81fe8ee43c61d


Copying blob sha256:0e4be1a7706aef4fb40db8b50c9174ffa98e5eb77430161a6b913b8d39681ec0


Copying blob sha256:e180137663d0922bdd1197723ad6d0deb3211a37d5c4f6fde12743639a569804


Copying blob sha256:e93d017dbb624cad4b217cf80e49b5c3fb3d6657604ef01cfc4c0093e4d779bc


Copying blob sha256:689fcce49498bf311ff3ad107ce4631c46132e7c6d41736a2efd1d3bc648218e


Copying blob sha256:cc18bb25f9b4fec4e264abff81a9fe2c3983d33123aede4af5ae19c0a965ac72


Copying blob sha256:3a416f05e656cfecfcf1c32e6885aecc0764a726da9d3a9d2c2a9863e9422d5a


Copying blob sha256:b24edc6713e62d4f42095929420491b7734f24ef3d37ab25c48d1a301289c105


Copying blob sha256:10b1b696718a327b8a2581f1399f19d725bae221a364083fa3f72c47c7ae1b95


Copying blob sha256:b81b2285e98fc9156e517e7374ad322fad9738131f810f161f0bd48248371805


Copying blob sha256:d9c0af72c6ed34e51f45cfa561a5e776fc3a20f938f7f4187f26e5ca1015c4fe


Copying blob sha256:89c3e7d01ec5560783177792803d88034e1cfbaf109425a6eda3007163c7d75b


Copying blob sha256:3542b0caf069b91fbf25455168534094df933a621c6c344d14d3ac33cbe44e3c


Copying blob sha256:6dbfda24bbbf2a76ed4792572a1659606fe43df23e9ba295e7af14da7628c604


Copying blob sha256:ba1668f9923b4ef206a17e5cc2b2d2220bcb1931fa8d636caec56ceb8683b440


Copying blob sha256:017396ce75261aec71bd36efe0d9b8362453f3147fbd889cf19d845cf4078115


Copying blob sha256:c8efcd5b2431ae1cb9bf86da372515e5ecb83473ca5352e168a28393210c24a7


Copying blob sha256:49a08729fde948a3a21c3fb929f133dc5765c43b63ad53272545d9d0c8c905a3


Copying blob sha256:495bc47f45ad9fd2527f7e1ba831f1663c03ed78453feed455e69e58ddbc7df7


Copying blob sha256:943304e9332068d75337b6025dcb2f4bdab8c0af3fca9a5dcf37881fc9afe5b9


Copying blob sha256:2d7857a255e46e4ad503370dd970a35a79c3ed6fe1a8bf58388ad6e80a88f3e0


Copying blob sha256:a56ebcdc4556e3e5b3ebbcab4f96d2be7a9edfaa6b7286d26ac33b5fe8e4ee04


Copying blob sha256:6928bae819e792526010653084e63a3faabab22428707f3372482ec15cc55803


Copying blob sha256:dba16e336c50470f8cb5c24b37cf72f161b1bb0ca36620567d63ebc458a9add9


Copying blob sha256:ad312c5c40ccd18a3c639cc139211f3c4284e568b69b2e748027cee057986fe0


Copying blob sha256:5d34979223330be17cb4899d009fdf43780c17cb84bfca0fa04325825c2331d9


Copying config sha256:44fee9e7f68f0573040a39837fa52bf1a6da69db89ca5e1dfcbb0f4aa46d54be


Writing manifest to image destination


44fee9e7f68f0573040a39837fa52bf1a6da69db89ca5e1dfcbb0f4aa46d54be


/usr/bin/sudo mkdir -p ./output


Building artifact(s)




/usr/bin/sudo podman run --rm --privileged --security-opt label=type:unconfined_t --volume /var/lib/containers/storage:/var/lib/containers/storage --volume ./output:/output --volume ./disk_config/disk.toml:/config.toml:ro quay.io/centos-bootc/bootc-image-builder:latest build --output /output --chown 1001:1001 --use-librepo=True --type qcow2 ghcr.io/wepantech/edu-os:latest


Generating manifest manifest-qcow2.json


Manifest generation step


2026/01/26 01:07:10 error: cannot build manifest: no default fs set: mount "/boot" requires a filesystem but none set


Error: Build process failed: The process '/usr/bin/sudo' failed with exit code 1

I activated 2FA in GitHub. Could it cause that? Or is there another problem?

(I hope, there is not too much information for hackers in the posted message. I don’t saw any. Please write, if there is.)

Thank you very much for help in advance!

Admitting this sounds like a cool project!

I assume that @j0rge would like to collect such topics and questions in github discussions rather than here, so just letting you know that posting there is an option too :slight_smile:

Thank you for the link! I opened a discussion!

By the way, and nothing against the image template, but check out Blue Blue if you haven’t seen it already. I use it for my custom images and love the features and ease of use.

Yea, the bluebuild folk have done a great job. I build them both ways.

Many thanks, I will take a look at it!

I already began to test my own image and rebased an old Silverblue installation on it.

rpm-ostree status shows me now “ostree-unverified-registry”.

Is that ok? I have set up cosign and generated a key as in the video is shown. Should rpm-ostree recognize it as verified?

If I recall, you’ll want to rebase to ostree-image-signed after rebooting. So if your current base is ostree-unverified-registry:$IMAGE_PATH:$IMAGE_TAG, then run

rpm-ostree rebase ostree-image-signed:$IMAGE_PATH:$IMAGE_TAG

There’s a little more info from Blue Build here: Building on Universal Blue | BlueBuild

1 Like

Thank you very much for the quick reply! It solved the problem!!

1 Like