Public Nix Container Images
openEduSuite no longer depends on upstream registries for its infrastructure images; every image is shipped as a reproducible Nix build. Each image is derived deterministically from source, is byte-for-byte reproducible, and can run fully offline, the baseline requirement for air-gapped university clusters.
The image family
All images follow the same pattern: a flat, multi-layer OCI container (dockerTools.buildLayeredImage) produced from a pinned Nix build of the respective upstream project. No distro base, no uncontrolled package list; just the binaries and libraries the Nix store layout provides.
| Image | Replaces | Version | Purpose |
|---|---|---|---|
dex |
ghcr.io/dexidp/dex |
2.38.0-nix | OIDC/OAuth2 identity provider (ArgoCD SSO) |
helmfile |
ghcr.io/helmfile/helmfile |
1.8.0-nix | Helmfile renderer for the ArgoCD CMP sidecar |
k8up |
ghcr.io/k8up-io/k8up |
2.13.1-nix | Kubernetes backup operator (Restic) |
cloudnative-pg |
ghcr.io/cloudnative-pg/cloudnative-pg |
1.30.1-nix | Postgres operator; injects the instance manager into every DB pod |
postgresql |
ghcr.io/cloudnative-pg/postgresql |
16.15-nix | CNPG-compatible PostgreSQL 16 (UID 26, /controller layout, barman-cloud) |
agentflow |
— (successor of taskfleet) | 0.1.0-nix | DAG-orchestrated coding-agent campaigns (af) |
Where to get them
Public primary registry (registry.openedusuite.org)
The complete, publicly reachable image family lives on the project's public OCI registry (Zot behind Traefik with a Let's Encrypt certificate):
https://registry.openedusuite.org/dex:2.38.0-nix
https://registry.openedusuite.org/helmfile:1.8.0-nix
https://registry.openedusuite.org/k8up:2.13.1-nix
https://registry.openedusuite.org/cloudnative-pg:1.30.1-nix
https://registry.openedusuite.org/postgresql:16.15-nix
https://registry.openedusuite.org/agentflow:0.1.0-nix
Pulls need no authentication; only pushing is access-controlled:
$ docker pull registry.openedusuite.org/k8up:2.13.1-nix
GHCR (public registry, planned)
Optionally the same images will also be published to ghcr.io/tobias-weiss-ai-xr/… (visibility & redundancy). Status: the GHCR push is blocked on a token with Packages: write scope.
ghcr.io/tobias-weiss-ai-xr/dex:2.38.0-nix
ghcr.io/tobias-weiss-ai-xr/helmfile:1.8.0-nix
ghcr.io/tobias-weiss-ai-xr/k8up:2.13.1-nix
ghcr.io/tobias-weiss-ai-xr/cloudnative-pg:1.30.1-nix
ghcr.io/tobias-weiss-ai-xr/postgresql:16.15-nix
ghcr.io/tobias-weiss-ai-xr/agentflow:0.1.0-nix
Mirror: Zot (cluster-internal)
Air-gapped target environments mirror the same image family onto a local Zot registry node, which also acts as a pull-through cache (example with an RFC 5737 documentation address):
192.0.2.10:5002/opendesk-nix/<name>:<tag>
The k3s registry mirror redirects every ghcr.io pull to Zot; the cluster remains self-sufficient even when external egress is down.
Why Nix?
- Reproducibility. An image is a function of the Nix flake inputs. Two builds of the same revision yield the same store path and therefore the same image digest.
- Minimality by construction, not by removal. A Nix image contains only what the store provides: the upstream Go binary, CA certificates,
tzdata. No package manager, no shell unless needed. - Air-gapped operation. Builds can be reconstructed offline from a nix copy closure; the Zot mirror decouples the cluster from external registries.
- Auditability. The derivation is the SBOM: every dependency is readable in the store path (
/nix/store/…-k8up-2.13.1).
Building it yourself
The derivations live in the openEduSuite-hrz repository under nix/images/infra/:
$ nix build .#k8up
$ skopeo copy --dest-tls-verify=false --format oci \
docker-archive:result \
docker://ghcr.io/tobias-weiss-ai-xr/k8up:2.13.1-nix
The flake pins nixpkgs via flake.lock; Go module hashes (vendorHash) and source hashes are fixed per derivation.
Notes on CNPG compatibility
The PostgreSQL image fulfils the CloudNativePG operator contract: UID/GID 26, /controller as working directory, /var/run/postgresql as socket directory, and barman-cloud for the backup path. The instance manager (as upstream) is not baked into the image; the operator injects it via the bootstrap-controller init container. For that purpose the operator image carries the binary at both locations (/manager and /controller/instance-manager).
Outlook
The image family grows with the suite's needs: application images (Intercom, the Stalwart fork, SOGo) are next on the same Nix path. The goal remains unchanged: a cluster that runs without a single imperative docker pull from foreign registries.