Anatomie eines selbst gehosteten Campus: openEDU auf einem Drei-Knoten-k3s-Cluster
Das Eingangstor der Deployment ist bewusst unspektakulär: eine einzige Anmeldeseite. Doch hinter diesem OIDC-Login unter home.openedu.graphwiz.ai verbirgt sich ein vollständiger, selbst hostbarer digitaler Arbeitsplatz für die Hochschullehre — Dokumente, Groupware, Chat, Videolehre, ein Learning-Management-System, kollaboratives Schreiben und KI im eigenen Rechenzentrum — betrieben auf drei Bare-Metal-Nodes mit 72 vCPU und rund 1 TB RAM. Kein Hyperscaler, keine SaaS-Abrechnung pro Sitzplatz, keine Daten, die die Organisation verlassen.
Dies ist ein Showcases dieser Deployment: was wo läuft, wie alles miteinander verwoben ist und welche operativen Lehren sich erst zeigen, wenn man das System wirklich betreibt.
Der Stack auf einen Blick
| Schicht | Wahl | Warum |
|---|---|---|
| OS | Ubuntu 24.04 LTS | langweilig, unterstützt, vorhersagbar |
| Kubernetes | k3s v1.36 | vollständige K8s-API, ein Bruchteil des operativen Gewichts |
| Ingress | HAProxy Ingress + MetalLB L2-VIP | eine stabile Eingangs-IP, kein Cloud-Load-Balancer nötig |
| TLS | cert-manager + Let's Encrypt (Wildcard) | ein Wildcard-Zertifikat, automatisch erneuert, von allen Ingresses geteilt |
| GitOps | Argo CD | sechs Applications, Clusterzustand = Git-Zustand |
| Identität | Keycloak (OIDC) + OAuth2 Proxy v7.15.4 | ein Login für jeden Dienst |
| Storage | lokale + RWO-Blockvolumes, S3-kompatible Backups (SeaweedFS) | einfach, in sich geschlossen |
| KI | Ollama (zwei Instanzen) + Open WebUI | Inferenz verlässt das Gebäude nie |
Die Suite hinter dem Portal
Das Portal selbst ist ein Dashboard. Nach der Anmeldung über OAuth2 Proxy, der an Keycloak via OpenID Connect delegiert, landen die Nutzer auf einer Seite mit Service-Kacheln. Jede Kachel führt zu einer Komponente des openEDU-Arbeitsplatzes:
- Dokumente und Kollaboration — Nextcloud 34 mit Collabora, CryptPad für kollaboratives Bearbeiten in Echtzeit.
- Kommunikation — Matrix (Synapse) mit Element für Chat, SOGo für Groupware und Mail.
- Lehre — Ilias als LMS, BigBlueButton und Jitsi für Videoseminare, JupyterHub für Kurs-Notebooks, Overleaf für kollaboratives LaTeX-Schreiben.
- Automatisierung und Betrieb — n8n für Workflow-Automatisierung, ein Fakturierungsdienst, Grafana-Dashboards für das Plattformteam.
Alles wird als Kubernetes-Manifeste in Namensräume pro Domäne deployet (openedu, llm, home, monitoring, backup), sodass eine defekte Komponente eingedämmt bleibt:
$ kubectl get ingress -A
NAMESPACE NAME HOSTS
home home-portal home.openedu.graphwiz.ai
argocd argocd argocd.home.openedu.graphwiz.ai
llm open-webui ai.home.openedu.graphwiz.ai
llm ollama-ingress ollama.home.openedu.graphwiz.ai
openedu ilias-ingress lms.home.openedu.graphwiz.ai
openedu invoicing invoicing.home.openedu.graphwiz.ai
monitoring grafana grafana.home.openedu.graphwiz.ai
Ein Hostname pro Dienst, ein Wildcard-Zertifikat, ein Login. Das ist das gesamte mentale Modell, das Nutzer brauchen.
Warum k3s auf Bare Metal
Der Cluster besteht aus drei Ubuntu-24.04-Nodes — einem Control-Plane- und zwei Worker-Nodes — verbunden mit k3s. Für eine Organisation ohne Plattformteam trifft k3s den Sweet Spot: die vollständige Kubernetes-API für Argo CD und cert-manager, ohne etcd-Aufzucht, Cloud-Control-Plane-Rechnungen oder eine dreizehn Komponenten umfassende Installation.
Der Verkehr tritt über eine MetalLB-Layer-2-VIP vor einem HAProxy-Ingress-Controller ein. Da die VIP im lokalen Netz annonciert wird, erhalten Dienste stabile interne Adressen ebenso wie öffentliche — nützlich für Dienste wie SMTP-Relay und Backup-Ziel, die gar nicht hinter einem HTTP-Ingress sitzen sollten.
TLS ist by design gelöst: ein einziger ClusterIssuer stellt ein Wildcard-Zertifikat von Let's Encrypt aus, jeder Ingress referenziert dasselbe Secret, und die Erneuerung ist unsichtbar:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
solver:
- dns01: {...}
Wildcard-Zertifikate sind die pragmatische Wahl für ein Deployment mit über zwanzig Hostnames. Die Alternative — eine Zertifikatsressource pro Ingress — ist „korrekter" und deutlich mühsamer.
GitOps, oder: Der Cluster ist ein Build-Artefakt
Argo CD verwaltet sechs Applications: das Portal, die openEDU-Suite, den Mailserver, die Plattform-Infrastruktur und benachbarte Produkt-Stacks. Nichts wird von Hand installiert. Eine Änderung ist ein Commit; Synchronisation ist deklarativ; Drift ist im Argo-CD-UI sichtbar.
Das zahlt sich vor allem bei Vorfällen und Migrationen aus. Als kürzlich eine Domänenmigration jede Komponente berührte, war die Lösung kein Runbook manueller kubectl edit-Beschwörungen — es waren aktualisierte Manifeste in Git, und Argo CD konvergierte. Die beiden echten Bugs auf dem Weg waren beide in Git, beide als Commits behebbar:
- Liveness-Probes, die logen. Die
httpGet-Probes des Kubelets beachten eine überschriebeneHost:-Header zuverlässig, also antwortete Nextcloud auf jede Probe mit 400 und geriet in eine Neustart-Schleife. Die Lösung war der Wechsel zuexec-Probes, die ein deterministischescurlim Container ausführen:
exec:
command:
- curl
- -fsS
- -H
- "Host: nextcloud.home.openedu.graphwiz.ai"
- http://localhost/status.php
- Nur bei Installation wirksame Umgebungsvariablen.
NEXTCLOUD_TRUSTED_DOMAINSkonfiguriert nur eine Neuinstallation. Domänenänderungen nach der Installation müssen überocc config:system:setlaufen — die Container-Env tut still nichts. Diese Bugklasse ist jede Stateful-Image wert zu wissen: Env-Variablen konfigurieren den Installer, nicht die Anwendung.
Stateful Pods debuggen ohne Magie
Die Daten der Suite liegen auf RWO-Persistent Volumes (Read-Write-Once). Als die Datenbank von Synapse nach der Domänenmigration operiert werden musste, konnte sich kubectl debug nicht einfach an das Volume hängen — ein RWO-Volume ist an genau einen Node gebunden. Das funktionierende Muster: einen Scratch-Pod an den konkreten Node pinnen, der das Volume-Attachment hält, die PVC mounten und von dort arbeiten.
$ kubectl get volumeattachments | grep pvc-synapse-data
$ kubectl debug -it node/<holding-node> --image=alpine \
-- mount /dev/vol /mnt && sqlite3 /mnt/homeserver.db
Nichts davon ist exotisch. All das ist im Repo dokumentiert, direkt neben den Manifesten, die es betraf — genau das ist der Punkt. Ein Deployment, das ein kleines Team betreut, kann sich kein Stammeswissen leisten.
KI im eigenen Haus als Erstrang-Bürger
Zwei Ollama-Instanzen sitzen hinter eigenen Ingresses, mit Open WebUI davor für die interaktive Nutzung. Modelle werden lokal gezogen und ausgeliefert; Prompts von Forschenden durchqueren nie eine Drittanbieter-API. Für einen Sektor, an GDPR und institutionelle Vertraulichkeit gebunden ist, ist lokale Inferenz kein Nice-to-have — sie ist der Grund, warum das Deployment KI-Funktionen überhaupt anbieten kann. Kombiniert mit n8n für Automatisierung lassen sich lokale Modelle zu Workflows verketten, ohne eine einzige externe Abhängigkeit.
Was der Betrieb kostet
Die ehrliche Abrechnung eines selbst gehosteten Campus:
- Hardware: drei Nodes, bereits abgeschrieben — Kapazität übrig bei 72 vCPU/1 TB.
- Personal: der echte Kostenfaktor. Eine Person mit Plattform-Denke kann das betreiben; anderthalb machen es bequem.
- Lizenzen: null. Jede Komponente ist Open Source.
- Cloud-Ausgaben: eine Domäne, DNS-Hosting, sonst nichts.
Die Trade-offs sind ebenso ehrlich: man besitzt Patchen, Kapazitätsplanung und Disaster Recovery. Backups gehen nach Zeitplan an ein S3-kompatibles Ziel (SeaweedFS), Restores werden geprobt und — der Schritt, den alle auslassen — der Restore-Pfad wird mit derselben Strenge getestet, wie die Backups genommen werden.
Fazit
Ein glaubwürdiger Open-Source-Digitaler Arbeitsplatz für die Bildung braucht keinen Hyperscaler, kein Managed-Kubernetes-Angebot und keine Platform-Engineering-Abteilung. Er braucht: einen kleinen k3s-Cluster, GitOps von Tag eins, einen Identity Provider, Wildcard-TLS und die Disziplin, den gesamten Stack in Git zu halten. Anfangen mit Portal und IdP — sobald Single Sign-on funktioniert, ist jeder weitere Dienst nur ein Manifest und ein DNS-Eintrag.
Der hier beschriebene Stack ist die Infrastruktur hinter openEDU, einem Open-Source-Digitalen Arbeitsplatz für Hochschulen. Der interaktive Überblick über das Ökosystem lebt unter landscape.openedu.graphwiz.ai.