Add coturn Deployment with hostNetwork mode and init container for secret substitution. Include SOPS-encrypted shared secret, TLS certificate for turn.axion1337.chat, and Synapse TURN configuration with proper relay URIs and credentials. Resolves DTLS timeout issues in RTC video calls by providing media relay for clients behind NAT/Firewall. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
🚀 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
- Voraussetzungen & Lokale Tools
- Architektur & Logik des Stacks
- Aufbau des Repositories
- Das Deployment (Aktueller Stand)
- Nützliche Befehle
- Troubleshooting & Known Issues
1. Voraussetzungen & Lokale Tools
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)
brew install kubectl fluxcd/tap/flux sops age helm
🐧 Linux
# 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:
winget install Kubernetes.kubectl FluxCD.Flux Mozilla.sops age-encryption.age Helm.Helm
⚙️ Lokale Konfiguration
- Kubeconfig: Stelle sicher, dass die Datei
~/.kube/configmit den Zugangsdaten zu deinem K3s-Cluster gefüllt ist. Test:kubectl get nodes. - SOPS Key: Du benötigst den privaten
age-Key (oder GPG-Key), der in der.sops.yamldes Repositories hinterlegt ist, um Secrets bearbeiten zu können.
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: Erlaubt es, Passwörter (z.B. SMTP) verschlüsselt in Git zu speichern. Flux entschlüsselt diese "on the fly" im Cluster.
- 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.
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): Der Web-Client für die Endnutzer. - Matrix RTC (
mrtc.): Die SFU (Selective Forwarding Unit) für Audio-/Video-Calls. - PostgreSQL: Die relationale Datenbank für Synapse und MAS.
3. Aufbau des Repositories
Das Repository ist strikt nach "Infrastruktur" und "Applikation" getrennt, um Abhängigkeiten korrekt zu laden.
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-secrets.sops.yaml # Als verschlüsseltes SOPS-Secret
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.
# 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:
serverNamemuss an der Wurzel stehen.- Komponenten werden in
camelCasegeschrieben (elementWeb,synapseAdmin). - Zertifikate werden durch
certManager: trueautomatisch gemanaged. Keine manuellen TLS-Einträge im Ingress-Block!
# 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-custom-secrets
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:
flux reconcile kustomization flux-system --with-source
flux reconcile kustomization production-apps --with-source
🔍 Status des Deployments prüfen
# 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
# 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 <name> -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):
sops apps/production/custom-configs/mas-secrets.sops.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 Chartnamenmatrix-stackverwenden.
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.
tlsdarf nicht in den Ingress-Block der Komponenten.serverNamemuss ins Top-Level, nicht untersynapse.- 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(aufaxion1337.chat) undwellKnownDelegation(ebenfalls aufaxion1337.chat) gleichzeitig aktiviert sind, fordertcert-managerzeitgleich 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: falseim Helm-Chart setzen. Das.well-known/matrix/serverFile 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: trueauf der obersten (Root-)Ebene dervaluessetzen. Das Chart erstellt daraufhin die korrekten Ingress-Annotations und Secrets von selbst.