# 🚀 Element Server Suite (ESS) Community – GitOps Deployment Guide Dieses Repository enthĂ€lt die Infrastruktur-as-Code (IaC) fĂŒr den Matrix-Homeserver (basierend auf der Element Server Suite Community Edition), der per **FluxCD** nach GitOps-Prinzipien verwaltet wird. ## 📑 Inhaltsverzeichnis 1. [Voraussetzungen & Lokale Tools](#1-voraussetzungen--lokale-tools) 2. [Architektur & Logik des Stacks](#2-architektur--logik-des-stacks) 3. [Aufbau des Repositories](#3-aufbau-des-repositories) 4. [Das Deployment (Aktueller Stand)](#4-das-deployment-aktueller-stand) 5. [NĂŒtzliche Befehle](#5-nĂŒtzliche-befehle) 6. [Troubleshooting & Known Issues](#6-troubleshooting--known-issues) 7. [Weitere Ressourcen](#7-weitere-ressourcen) ----- ## 1\. Voraussetzungen & Lokale Tools **Empfohlen: `.devcontainer/` nutzen** ("Reopen in Container" in VS Code, oder `docker build` + `docker run` manuell, siehe [`.devcontainer/README.md`](.devcontainer/README.md)) - bringt alle unten genannten Tools bereits fertig eingerichtet mit, ohne sie lokal zu installieren. Alternativ, um mit diesem Stack zu interagieren (Konfigurationen anzupassen, Secrets zu verschlĂŒsseln, Fehler zu suchen), mĂŒssen folgende Tools lokal installiert sein: ### đŸ› ïž Benötigte CLI-Tools * **`kubectl`**: FĂŒr die direkte Kommunikation mit dem Kubernetes-Cluster. * **`flux`**: FĂŒr das manuelle Anstoßen von GitOps-Synchronisationen. * **`sops`** & **`age`** (oder GPG): FĂŒr die Ver- und EntschlĂŒsselung von Secrets direkt im Git-Repo. * **`helm`**: (Optional) Zum Inspizieren von Chart-Values. ### 🍏 macOS (via Homebrew) ```bash brew install kubectl fluxcd/tap/flux sops age helm ``` ### 🐧 Linux ```bash # kubectl & helm via Paketmanager (apt/dnf) oder curl curl -sLS https://fluxcd.io/install.sh | sudo bash # SOPS wget https://github.com/getsops/sops/releases/download/v3.8.1/sops-v3.8.1.linux.amd64 sudo mv sops-v3.8.1.linux.amd64 /usr/local/bin/sops && sudo chmod +x /usr/local/bin/sops sudo apt install age ``` ### đŸȘŸ Windows (via Winget oder WSL2) *Empfehlung: Nutze WSL2 (Ubuntu) und folge den Linux-Schritten.* Nativ via Winget: ```powershell winget install Kubernetes.kubectl FluxCD.Flux Mozilla.sops age-encryption.age Helm.Helm ``` ### ⚙ Lokale Konfiguration 1. **Kubeconfig:** Stelle sicher, dass die Datei `~/.kube/config` mit den Zugangsdaten zu deinem K3s-Cluster gefĂŒllt ist. Test: `kubectl get nodes`. 2. **SOPS Key:** Du benötigst den privaten `age`-Key (oder GPG-Key), der in der `.sops.yaml` des Repositories hinterlegt ist, um Secrets bearbeiten zu können. 3. **Git Hooks installieren:** Nach dem Klonen dieses Repositories mĂŒssen Git Hooks installiert werden, um ConfigMap-Änderungen automatisch zu tracken: ```bash cd prod/gitops ./scripts/install-hooks.sh ``` Siehe [📖 GitOps ConfigMap Auto-Sync](docs/ops-configmap-sync.md) fĂŒr Details. ----- ## 2\. Architektur & Logik des Stacks Das Setup basiert auf einer modernen, modularen GitOps-Architektur: ### Management-Komponenten * **K3s**: Die leichtgewichtige Kubernetes-Distribution, die als Fundament dient. * **FluxCD**: Der GitOps-Controller. Er ĂŒberwacht dieses Git-Repository. Ändert sich hier eine Datei, wendet Flux die Änderung automatisch im Cluster an. * **SOPS + age**: Erlaubt es, Secrets verschlĂŒsselt in Git zu speichern. Flux entschlĂŒsselt diese "on the fly" im Cluster. Mehrere Secrets nutzen zusĂ€tzlich einen zweiten, eng gescopten age-Key fĂŒr automatisierte Rotation (siehe coturn TURN-Secret unten). * **Traefik**: Der Ingress-Controller (Standard bei K3s). Er leitet Traffic von Port 80/443 an die richtigen internen Pods weiter. * **Cert-Manager**: Spricht mit Let's Encrypt und stellt automatisch gĂŒltige TLS-Zertifikate fĂŒr alle Ingress-Routen aus. * **NetworkPolicies**: Default-Deny Ingress fĂŒr die `matrix`- und `authentik`-Namespaces, mit expliziten Allow-Regeln pro Komponente (`apps/production/networkpolicy.yaml`, `apps/authentik/networkpolicy.yaml`). ### Matrix Stack (ESS Community v26.4.0) Die Suite ist ein "Umbrella Chart", das aus mehreren Microservices besteht: * **Synapse (`matrix.`):** Das eigentliche Backend (Homeserver) fĂŒr die Chat-Nachrichten. * **Matrix Authentication Service (MAS) (`account.`):** Der OIDC-basierte Login-Server. Zwingend erforderlich fĂŒr moderne Matrix-Clients. * **Element Web (`domain.tld`):** Eigener Fork (`sorb/threadnet-web`) des Web-Clients fĂŒr die Endnutzer - Custom Themes, Element Desktop Setup-Seiten, Element-Call-Anpassungen. * **Matrix RTC (`mrtc.`):** Die SFU (Selective Forwarding Unit) fĂŒr Audio-/Video-Calls, mit eigenem Element-Call-Fork (`sorb/threadnet-call`) fĂŒr höhere Video-Defaults (bis 1440p/60fps). * **coturn:** TURN/STUN-Server fĂŒr WebRTC hinter NAT (`hostNetwork: true`, außerhalb der NetworkPolicy-Kontrolle, stattdessen ĂŒber die Hetzner Cloud Firewall abgesichert). Shared Secret wird monatlich automatisiert rotiert. * **PostgreSQL:** Die relationale Datenbank fĂŒr Synapse und MAS. ### Identity & Observability * **Authentik** (`auth.`, `account.`): OIDC-Identity-Provider fĂŒr Matrix-Enrollment, Passwort-Recovery und optionales 2FA/Passkey. Flows/Provider/Application deklarativ als Authentik-Blueprints erfasst (`apps/authentik/authentik-blueprints.yaml`), nicht nur in der UI geklickt. * **Monitoring**: Grafana Alloy sammelt Metriken/Logs, Remote-Write zu einem externen Prometheus/Loki-Stack. * **Backups**: NĂ€chtliche, verschlĂŒsselte & deduplizierte Borg-Backups (Postgres-Dumps + Synapse-`media_store`) zu einer Hetzner Storage Box, getrennt nach Namespace, mit eigenen Repos/Passphrasen. ### Moderation & Content Scanning * **Draupnir**: Moderationsbot (Community-Nachfolger von Mjolnir) fĂŒr Ban-Listen/Policy-Rooms. * **ClamAV**: Zwei Bausteine fĂŒr unterschiedliche RĂ€ume - ein eigenes Synapse-Modul (`clamav_spam_checker.py`) scannt Uploads in unverschlĂŒsselten RĂ€umen; ein zusĂ€tzlicher, eigenstĂ€ndiger `clamav-http-scanner`-Dienst wird vom gepatchten Element-Web-Client (`sorb/threadnet-web`) sowohl beim Senden als auch beim Empfangen aufgerufen und deckt damit auch verschlĂŒsselte RĂ€ume/DMs ab. Details: `docs/deployment-guides/06-moderation-content-scanning.md`. ### Host-Level (nicht-GitOps) Änderungen * `host-config/` ist bewusst der einzige Teil dieses Repos, den Flux **nicht** verwaltet - Skripte/systemd-Units, die direkt auf dem nackten Hetzner-Host laufen (z.B. `unattended-upgrades`-Vorab-Benachrichtigungen), fĂŒr Dinge, die strukturell außerhalb der Reichweite von Flux liegen. Deployment erfolgt manuell per SSH, instanzspezifische Werte liegen in einer Config-Datei auf dem Host, nicht im versionierten Skript. Details: `docs/deployment-guides/07-host-maintenance-notifications.md`. ----- ## 3\. Aufbau des Repositories Das Repository ist strikt nach "Infrastruktur" und "Applikation" getrennt, um AbhĂ€ngigkeiten korrekt zu laden. ```text gitops/ ├── .sops.yaml # Definiert, wie Secrets verschlĂŒsselt werden ├── clusters/matrix/ # Der Einstiegspunkt fĂŒr FluxCD ├── apps/ │ ├── base/ │ │ ├── infra/ # Core-Dienste (Cert-Manager, Namespaces) │ │ └── matrix/ # Die OCI Helm-Repository Definition fĂŒr ESS │ └── production/ # Das eigentliche Matrix-Deployment │ ├── kustomization.yaml # Inhaltsverzeichnis │ ├── element-server-suite.yaml # Das HelmRelease (Bestellung an Flux) │ ├── cert-issuer.yaml # Let's Encrypt Konfiguration │ ├── matrix-postgres-auth.yaml # DB-Passwörter │ └── custom-configs/ # Eigene Anpassungen (Themes, Logging) │ ├── synapse-values.yaml # Als ConfigMap │ ├── element-values.yaml # Als ConfigMap │ └── mas-secret.yaml # Als verschlĂŒsseltes SOPS-Secret ``` Weitere Secret-Dateien liegen direkt unter `apps/production/` bzw. `apps/authentik/` (z.B. `coturn-secret.yaml`, `synapse-turn-secret.yaml`, `synapse-backup-secret.yaml`, `authentik-backup-secret.yaml`) - jede einzeln SOPS-verschlĂŒsselt, nicht in `custom-configs/` gebĂŒndelt. ### Repo-Topologie (seit 2026-07-31) **Kanonisch ist `git.lab/axion1337.chat/axion1337.chat-gitops`** (Homelab-GitLab, nur im Lab auflösbar) — dort wird gepusht und lĂ€uft der CI-Verifikations-Job (`.gitlab-ci.yml`). Die Kopie auf `rohana.axion1337.de` ist ein automatischer **Push-Mirror** und bleibt die **Flux-Quelle**: der Cluster zieht unverĂ€ndert von Gitea, der Mirror liefert. **Niemals direkt nach rohana pushen** — der Mirror ĂŒberschreibt divergente StĂ€nde. **Issues und Wiki liegen seit 2026-08-01/02 ebenfalls auf git.lab** ([Issues](https://git.lab/axion1337.chat/axion1337.chat-gitops/-/issues) · [Wiki](https://git.lab/axion1337.chat/axion1337.chat-gitops/-/wikis/home) — der Wiki-Reiter oben im Projekt). ⚠ Die Issue-Nummern haben sich beim Umzug verschoben; ein alter Verweis „gitops#N" meint die Gitea-Nummer, verbindlich ist der Migrations-Fußtext im jeweiligen Issue. **Releases bleiben auf Gitea** (öffentlicher Download-Pfad). Der `wiki`-Branch in diesem Repo ist ein **ĂŒberholter Abzug von `docs/` aus dem Mai** und nicht die gepflegte Fassung. Alle Dokumentationsquellen zusammen (Plattform, Homelab, Arbeitsweise) gibt es unter **[wiki.lab](https://wiki.lab)** — Konfiguration im Repo [`homelab/wiki`](https://git.lab/homelab/wiki). **AbhĂ€ngigkeits-Logik:** Flux installiert erst `infra-apps` (damit Namespaces und Repositories existieren) und danach `production-apps` (das eigentliche ESS-Chart). ----- ## 4\. Das Deployment (Aktueller Stand) ### Das HelmRepository (OCI) Element verteilt die Community-Edition modern ĂŒber die GitHub Container Registry (`ghcr.io`). Klassische HTTP-Helm-Repos werfen hier oft 404-Fehler. ```yaml # apps/base/matrix/ess-repo.yaml apiVersion: source.toolkit.fluxcd.io/v1 kind: HelmRepository metadata: name: element-ess-oci spec: type: oci url: oci://ghcr.io/element-hq/ess-helm ``` ### Das HelmRelease (Das HerzstĂŒck) Das ESS-Chart (`v26.4.0`) hat ein extrem striktes JSON-Schema. Konfigurationen mĂŒssen exakt sitzen: * `serverName` muss an der Wurzel stehen. * Komponenten werden in `camelCase` geschrieben (`elementWeb`, `synapseAdmin`). * Zertifikate werden durch `certManager: true` automatisch gemanaged. **Keine manuellen TLS-EintrĂ€ge im Ingress-Block\!** ```yaml # apps/production/element-server-suite.yaml (Auszug) apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: name: matrix-stack spec: chart: spec: chart: matrix-stack version: "26.4.0" valuesFrom: - kind: ConfigMap name: ess-synapse-custom valuesKey: values.yaml - kind: Secret name: ess-mas-values-secret valuesKey: values.yaml - kind: Secret name: synapse-turn-secret valuesKey: values.yaml values: serverName: axion1337.chat certManager: true postgres: enabled: true synapse: enabled: true ingress: { host: matrix.axion1337.chat } matrixAuthenticationService: enabled: true ingress: { host: account.axion1337.chat } elementWeb: enabled: true ingress: { host: axion1337.chat } wellKnownDelegation: enabled: false # ! WICHTIG (Siehe Troubleshooting) ``` ----- ## 5\. NĂŒtzliche Befehle ### 🔄 Flux / GitOps Sync erzwingen Wenn man nicht auf den automatischen 10-Minuten-Timer von Flux warten will: ```bash flux reconcile kustomization flux-system --with-source flux reconcile kustomization production-apps --with-source ``` ### 🔍 Status des Deployments prĂŒfen ```bash # Zeigt, ob Flux das Chart akzeptiert und angewendet hat flux get helmreleases -A # Zeigt an, ob die Pods erfolgreich starten kubectl get pods -n matrix ``` ### 🔐 Zertifikate (Let's Encrypt) debuggen ```bash # Sind die Zertifikate da und gĂŒltig? kubectl get certificate -n matrix # Wo hĂ€ngt der Request? (403 Fehler etc.) kubectl get certificaterequest -n matrix kubectl get challenges -n matrix kubectl describe challenge -n matrix ``` ### đŸ›Ąïž Secrets mit SOPS bearbeiten Um ein Passwort im GitOps-Repo zu Ă€ndern, editiert man die verschlĂŒsselte Datei direkt via SOPS (sie wird transparent entschlĂŒsselt und beim Speichern wieder verschlĂŒsselt): ```bash sops apps/production/custom-configs/mas-secret.yaml ``` ----- ## 6\. Troubleshooting & Known Issues ### Issue 1: `HelmChart is not ready: stat ... no such file or directory` * **Ursache:** Falscher Versuch, das Chart direkt aus dem GitHub-Repo-Code (als GitRepository) zu lesen. Das Chart erfordert Sub-Charts, die so nicht gerendert werden können. * **Lösung:** Immer das OCI-Repository (`oci://ghcr.io/...`) und den Chartnamen `matrix-stack` verwenden. ### Issue 2: `values don't meet the specifications of the schema(s)` * **Ursache:** Ab Version 26.x hat ESS ein sehr rigides JSON-Schema. * **Lösung:** Logs genau lesen. * `tls` darf nicht in den Ingress-Block der Komponenten. * `serverName` muss ins Top-Level, nicht unter `synapse`. * Keine `config:` Blöcke fĂŒr Core-Komponenten. ### Issue 3: Let's Encrypt Error `403 Order's status is processing` auf der Hauptdomain * **Ursache (Die ACME Race Condition):** Wenn `elementWeb` (auf `axion1337.chat`) und `wellKnownDelegation` (ebenfalls auf `axion1337.chat`) gleichzeitig aktiviert sind, fordert `cert-manager` zeitgleich zwei Zertifikate fĂŒr dieselbe Domain an. Let's Encrypt blockt den zweiten Versuch und das Ingress-Setup hĂ€ngt sich auf. * **Lösung:** `wellKnownDelegation: enabled: false` im Helm-Chart setzen. Das `.well-known/matrix/server` File muss stattdessen entweder als statische JSON-Datei auf dem Webserver der Hauptdomain hinterlegt oder per Ingress-Route (Traefik Middleware) direkt auf den Synapse-Dienst umgebogen werden. ### Issue 4: Fehlende Zertifikate (`No resources found`) * **Ursache:** Manuelle Kustomize-Patches kollidieren mit dem Helm-Chart. * **Lösung:** Manuelle Patches löschen und das native Feature des Charts nutzen: `certManager: true` auf der obersten (Root-)Ebene der `values` setzen. Das Chart erstellt daraufhin die korrekten Ingress-Annotations und Secrets von selbst. ----- ## 7\. Weitere Ressourcen * **`CLAUDE.md`** (Repo-Root): Technische Referenz fĂŒr KI-gestĂŒtzte Arbeit an diesem Repo - Architektur, bekannte Chart-Quirks, Troubleshooting-Checkliste. * **`docs/TASKS.md`**: Backlog-Pointer zu den [Gitea Issues](https://rohana.axion1337.de/sorb/axion1337.chat-gitops/issues) - Details werden nicht mehr doppelt gepflegt. * **[Gitea Releases](https://rohana.axion1337.de/sorb/axion1337.chat-gitops/releases)**: Versionshistorie (SemVer, `vMAJOR.MINOR.PATCH` als ÄnderungsgrĂ¶ĂŸen-Konvention, kein KompatibilitĂ€tsvertrag - siehe [[00-TASKS]] Wiki fĂŒr die Konvention). * **[Wiki](https://git.lab/axion1337.chat/axion1337.chat-gitops/-/wikis/home)** (auf git.lab, Reiter *Wiki*): AusfĂŒhrliche Historie, Incident-Notizen, Setup-Guides pro Komponente. Zusammen mit Homelab- und Verfahrensdoku auch unter **[wiki.lab](https://wiki.lab)**. * **`docs/deployment-guides/`**: Detaillierte Guides fĂŒr TURN-Server, Authentik, Monitoring, Element-Customization, Room-Policies, Moderation & Content-Scanning, Host-Wartungsbenachrichtigungen.