A neutral, self-hosted media platform for a library you own and are entitled to stream. Bring your own files — Zaentrum catalogs, processes, and streams them to clean clients on the web, your phone/tablet, and your TV.
This repo is the front door: how to install, the release channels, and pointers to the rest of the project.
Product page → zaentrum.github.io/zaentrum · Docs → the wiki
Status: 0.x. Releases are tagged across every repository at once, and the
stablechannel inreleases.jsonnames the newest; every image is also published frommainaslatest, whichedgeserves. The commands below run the newest build ofmain; releases has the same for a release.
docker run -d --privileged --restart unless-stopped -p 80:80 --name zaentrum \
ghcr.io/zaentrum/appliance:latest
open http://zaentrum.localhostThat single container runs the whole platform: a full Kubernetes (k3s) in-process, the
operator, and everything the operator brings up — the portal, the web app, the catalog and
its consoles, streaming, and bundled Keycloak, Postgres, Valkey and Kafka. One
image, one port, nothing else to install; the first boot pulls the platform's images from
ghcr.io and takes a few minutes. The image is linux/amd64 only, and it needs host port
80: the platform's ingress and its sign-in are bound to http://zaentrum.localhost — no
other name, no other port. The library and the bundled Postgres — the catalog, the accounts,
the settings — keep their data on volume claims inside the container, so a restart keeps them;
replacing the container starts an empty platform
(persistence).
The first run is three steps
(self-hosting → first run), and after you sign in the
portal's Set Up Your Server checklist walks you through them: sign in as admin with the
one-time password the operator generated for this install, and choose your own when Keycloak
asks; save a TMDB key (the images carry none); then copy your files into the library and scan. The password is in Secret
zaentrum-keycloak-admin, key realm-admin-password:
docker exec zaentrum kubectl -n zaentrum get secret zaentrum-keycloak-admin \
-o jsonpath='{.data.realm-admin-password}' | base64 -d; echoSign-in needs https everywhere except on the machine itself. Keycloak marks its login
cookies Secure, and a browser keeps those over plain http for localhost names only — over
http://<lan-ip> or http://<name>.local, Keycloak answers the login form with "Cookie not
found" and nobody signs in. The Android phone and TV apps go further: they refuse plain http
altogether, and trust public certificate authorities only.
So the appliance, which serves plain http at zaentrum.localhost, is for the machine it runs
on. To reach Zaentrum from other devices, run it under a real hostname with TLS: the operator on
a cluster whose ingress terminates https with a certificate the devices trust (spec.hostname
and identity.issuerScheme: https — see
self-hosting). Clients use Add Server
with that address. LAN deployment profiles — the server's IP, a wildcard DNS name, mDNS — are
designed (ADR-0008) but not built, and as
designed they serve plain http, which cannot sign in.
Out of the box Zaentrum runs its own bundled Keycloak (realm zaentrum), and you manage
users in Keycloak's admin console. The console is not on the public host, which routes only
the sign-in paths (/auth/realms, /auth/resources) to Keycloak: reach it through a
port-forward, at http://localhost:8080/auth/admin/, as the master realm's bootstrap admin, and
switch to the realm zaentrum there (the admin console),
or publish it with identity.exposeAdminConsole: true. On a cluster you can instead use your
own OIDC provider directly: identity.mode: external on the Zaentrum
CR, with your provider's issuer and client, and no Keycloak is rendered. Those are the two modes
the CRD accepts. Federating your provider through the bundled Keycloak (broker,
ADR-0007) is designed, not built.
The same platform runs on any Kubernetes cluster via the operator, which reconciles the
whole stack from a single custom resource. Install it once, as cluster-admin, from an install
manifest — the CRDs, the cluster RBAC and the controller — then apply a Zaentrum CR:
# the newest release, for the stable channel (the default)
kubectl apply -f https://github.com/zaentrum/zaentrum-operator/releases/latest/download/operator-install.yaml
# …or the newest build of main, pinned to one operator:sha-<commit>, for edge:
# kubectl apply -f https://raw.githubusercontent.com/zaentrum/zaentrum-operator/main/deploy/operator-install.yaml
kubectl create namespace zaentrum
kubectl apply -f zaentrum.yaml # your Zaentrum CR — see docs/self-hosting.md
# or install the OLM bundle on OpenShift — see the operator repo's operator/bundleFull deployment & operations docs live in docs/ — start there. It routes
by audience and covers every path:
- docs/README.md — index + the four-layer deploy model
- Prerequisites — cluster + external dependencies
- Self-hosting — appliance · your-own-k8s · helm (+ values reference; the old k3s/Compose profiles are unsupported)
- Operator & CR reference — the operator + the complete
ZaentrumCR spec - Reference demo — a worked operator + CI GitOps deploy
- Updating — day-2: app image · chart/operator roll · CR change
- Troubleshooting — symptom → cause → fix
- Architecture — how it fits together
A release is one tag, vX.Y.Z, in every repository of the platform: each image at :vX.Y.Z
and :X.Y, the operator's install manifest, the appliance ghcr.io/zaentrum/appliance:vX.Y.Z,
the OLM bundle and catalog, and the zae CLI. There are two release channels, in
releases.json, which every operator reads:
stable(the default) names the newest release. A new install starts on it; in manual mode (the default) an install keeps the version it runs and reports the next release, in auto mode it moves on its own. A push tomainmoves nothing in it.edgeislatest, the newest build ofmain: the operator resolves eachghcr.io/zaentrum/*image to its current digest on every reconcile, and rolls the components whose image changed.
spec.version: vX.Y.Z pins an install to a release. What a release publishes, the channels in
full, and how a release is cut: docs/releases.md.
| Repo | What it is |
|---|---|
zaentrum/zaentrum (this) |
install, releases, instructions, the product page and the end-to-end tests — the front door |
zaentrum/zaentrum-operator |
the Kubernetes operator — controller + CRD + deploy templates + OLM bundle, and the appliance image |
zaentrum/<service> |
per-service repos (catalog, playback, web/mobile/TV clients, …) |