Container Registry

ZenoRegistry

Your Images. Your Infrastructure. Your Rules.

A self-hosted, OCI-compliant container registry built for internal enterprise use. Single Go binary with an embedded Svelte admin UI, S3-compatible blob storage, PostgreSQL metadata, OIDC SSO, and role-based access — no SaaS, no per-seat fees, no vendor lock-in.

100%
OCI Compliant
1
Binary, ~30 MB Image
2
External Deps (S3 + Postgres)
Philosophy

Boring on Purpose

A container registry should be a utility, not a platform. ZenoRegistry does exactly one thing — store and serve OCI images — and runs as a single binary with a Postgres connection string and an S3 bucket.

1binary
Server + Admin UI
0
Runtime Sidecars
S3
Any Compatible Backend
OIDC
Built-in SSO
Features

Everything a Private Registry Should Be

The OCI Distribution API done right, with the operational controls that internal platform teams actually need.

Full OCI Distribution API

Implements the complete OCI Distribution Specification: push, pull, tags, catalog, chunked uploads, cross-repo blob mounts, and manifest deletion. Works with Docker, Podman, nerdctl, and any compliant client.

S3-Compatible Storage

Pluggable storage driver backed by the AWS SDK Go v2. Works with AWS S3, MinIO, Ceph, DigitalOcean Spaces, Scaleway Object Storage, or any S3-compatible service. Content-addressable blob layout with directory fan-out.

OIDC Single Sign-On

Drop-in SSO for the admin dashboard via any OpenID Connect provider — Keycloak, Entra ID, Google Workspace, Authentik, Okta. Emergency local admin always available as break-glass.

Role-Based Access

Three clean roles: pull, push, and admin. JWT scopes are checked per repository and per action on every OCI request — not bolted on at the proxy layer.

Image Retention Policies

Per-repository policies: keep the last N tags, keep tags pushed in the last N days, never delete tags matching glob patterns like v* or latest, and a configurable safety floor. Always dry-run first.

Cosign-Aware

Supply-chain sibling tags (.sig, .att, .sbom) and multi-arch digest references are recognised, hidden from user-facing tag counts, and excluded from retention rules so signatures never get garbage-collected by accident.

Architecture

One Binary, Two Backends

The Go server, OCI API, admin REST API, and embedded Svelte 5 SPA all ship in a single binary. The only runtime dependencies are PostgreSQL for metadata and an S3-compatible bucket for blobs.

Layer 1

HTTP Router (chi/v5)

Dispatches /v2/* to the OCI Distribution handlers, /api/v1/admin/* to the admin REST API, and falls through to the embedded SPA for everything else.

Layer 2

Auth & Middleware

Bearer JWT for OCI clients, HTTP-only session cookies for the admin UI, OIDC code-exchange callbacks, bcrypt password hashing — all from a single TokenService.

Layer 3

Storage Driver

Interface-based design with an S3 driver for production and an in-memory driver for tests. Streaming uploads, chunked PATCHes, atomic completion, and content-addressable layout.

Layer 4

PostgreSQL Metadata

Users, roles, repositories, tag metadata, retention policies, and audit events — pgx connection pool with embedded auto-migrations on startup.

Layer 5

Embedded Svelte 5 Admin UI

Built with Vite, copied into internal/frontend/dist/, served via //go:embed. No separate process, no nginx in front, no static file mount.

OCI Distribution API

Standard Protocol, No Surprises

Every standard /v2/ endpoint is implemented. Push from any Docker daemon, pull from any cluster, and use any OCI-compliant tooling you already trust.

Push & Pull

HEAD/GET /v2/{name}/blobs/{digest}, PUT /v2/{name}/manifests/{ref}, chunked PATCH uploads, cross-repository blob mount — the full happy path for docker push and docker pull.

Catalog & Tag Listing

GET /v2/_catalog for repositories, GET /v2/{name}/tags/list for tags, with cursor-based pagination via n and last query parameters.

Manifest & Blob Deletion

DELETE /v2/{name}/manifests/{ref} for tags and digests. Garbage collection reclaims unreferenced blobs once nothing points at them.

Multi-Arch Images

Manifest lists / OCI image indexes are stored, served, and tracked correctly. Bare sha256-<hex> child references are hidden from the UI and excluded from retention.

Authentication

Two Front Doors, One Identity Store

Docker clients authenticate via the standard OCI Bearer token flow. Browsers log in via OIDC SSO or local admin. Both share the same PostgreSQL user and role tables.

OCI Bearer Token

  • Standard WWW-Authenticate challenge
  • Basic auth exchange at /v2/token
  • HMAC-SHA256 JWTs with scoped access claims
  • Configurable token lifetime (default 15 minutes)

Admin UI Sessions

  • HTTP-only, SameSite=Lax session cookies
  • Local admin login with bcrypt password hashing
  • Auto-provisioning of OIDC users on first login
  • Admin role required for the dashboard

OIDC SSO Providers

  • Keycloak, Authentik, Dex
  • Microsoft Entra ID, Okta
  • Google Workspace
  • Any standards-compliant OIDC IdP
Retention Policies

Storage That Doesn't Run Away From You

CI/CD pipelines push thousands of images per week. ZenoRegistry includes a built-in retention engine so storage cost stays bounded — with safe defaults, dry-run previews, and an audit trail for every automated deletion.

Policy Rules

  • keep_last — N most recent tags
  • keep_days — tags pushed in last N days
  • keep_patterns — glob protection (v*, latest, release-*)
  • keep_min — safety floor per repository

Safe by Design

  • No policy = no automatic deletion
  • Per-repository scoping with global default
  • Dry-run preview before any destructive run
  • Cosign signatures and SBOMs never deleted

Auditability

  • Per-tag push timestamps tracked in Postgres
  • Reason recorded for each retention decision
  • Structured JSON logs via log/slog
  • Pair with ZenoAudit for tamper-evident trails
Admin Dashboard

An Admin UI That Comes With the Binary

A modern Svelte 5 SPA — compiled to static assets and embedded into the Go binary — covers everything operators need without a second service to deploy.

Dashboard

At-a-glance counts of users, repositories, storage usage, and recent activity.

User Management

Create, edit, and disable users. Assign and revoke roles. Reset passwords for local accounts.

Repository Browser

Search and filter repositories. Drill into tags. Delete tags or whole repositories with confirmation dialogs.

Retention Policy Editor

Configure policies per repository, preview the deletion candidates, and execute the run from a single screen.

Operations

Production-Ready Out of the Box

Designed by people who have run registries in anger. The boring operational details are handled, not punted to the operator.

Health Endpoint

GET /healthz for Kubernetes liveness and readiness probes. Always-on, dependency-free.

Graceful Shutdown

Clean connection draining on SIGINT and SIGTERM — no half-finished blob uploads when you roll a deployment.

Structured JSON Logs

Native log/slog output with request IDs, user context, and consistent field names. Drop straight into Loki, Elasticsearch, or ZenoLog.

Embedded Auto-Migrations

PostgreSQL schema migrations run automatically on startup. No separate migrator container, no manual SQL to apply.

Native TLS

Point the server at a certificate and key and it serves HTTPS directly — no sidecar proxy required for the simple case.

Kubernetes Friendly

Plain Deployment + Service + ConfigMap + Secret. A small image, env-var configuration, and a health endpoint — no operator to install.

Tech Stack

Picked for Boring, Not Hype

Every dependency is a load-bearing choice — battle-tested libraries with active maintenance and predictable behaviour.

Layer Technology
Language Go 1.25
HTTP Router chi/v5
Database PostgreSQL 16 via pgx/v5
Object Storage S3 (AWS SDK Go v2) — AWS, MinIO, Ceph, Spaces
Auth golang-jwt/v5, bcrypt, coreos/go-oidc/v3
Frontend Svelte 5 (runes), Vite 8
Logging log/slog (structured JSON)
Container Image Multi-stage build on Alpine 3.21, ~30 MB
Use Cases

Built For

ZenoRegistry is the right answer when you want full control over your container images without the operational weight of a SaaS or an enterprise registry platform.

Internal Platform Teams

Give every team a private registry namespace. Push from CI/CD, pull from clusters, manage access through the IdP you already have.

Sovereign & Air-Gapped Deployments

European data sovereignty, regulated industries, disconnected environments. Single binary plus Postgres plus object storage — that's the whole stack.

GitOps Source of Truth

Argo CD and Flux pull from the registry. ZenoRegistry plays nicely as the single image source for an entire Kubernetes estate.

Cosign & Supply Chain

Store image signatures, SBOMs, and attestations as cosign sibling tags. ZenoRegistry recognises them, hides them from UI clutter, and never garbage-collects them by accident.

ZenoKube Integration

Ships as one of the core services in the ZenoKube sovereign cloud platform — your cluster's own registry, on your hardware, behind your IdP.

Self-Hosted Replacement for SaaS

Drop-in alternative to GitHub Container Registry, GitLab Container Registry, Harbor, or Quay when you want fewer moving parts and no per-seat invoice.

Take Your Container Images Back

Run your own OCI registry on your own infrastructure, with SSO from your own IdP and storage in your own bucket. Contact us for a demo, a managed deployment, or a self-hosted licence.