Installation
Diese Seite bringt dich von einem leeren Cluster zu einer laufenden, über HTTPS erreichbaren Hoppla-Instanz mit funktionierendem Mailversand.
Cluster-Voraussetzungen
Das Chart erwartet, dass ein Ingress-Controller, cert-manager und ein ClusterIssuer bereits existieren (das Small-Profil verweist auf clusterIssuer: letsencrypt-prod). Auf einem frischen Cluster installierst du diese einmalig, bevor du ./install.sh ausführst.
Dein Cluster braucht außerdem ausgehenden Internetzugang für die Monitoring-Worker -- ein IPv4-only-Cluster genügt und muss nicht konfiguriert werden. Wenn du IPv6-Hosts überwachen willst, lies Netzwerk & IP-Versionen, bevor du den Cluster anlegst: Bei GKE und EKS wird die IP-Familie beim Erstellen festgelegt und ist danach nicht mehr änderbar.
# 1. ingress-nginx (sein LoadBalancer-Service liefert dir die externe IP für DNS)
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx --create-namespace \
--set controller.service.type=LoadBalancer --wait
# 2. cert-manager (+ CRDs)
helm repo add jetstack https://charts.jetstack.io
helm upgrade --install cert-manager jetstack/cert-manager \
--namespace cert-manager --create-namespace --set crds.enabled=true --wait
# 3. der letsencrypt-prod ClusterIssuer, auf den das Chart verweist
kubectl apply -f - <<'EOF'
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata: { name: letsencrypt-prod }
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: [email protected] # <-- deine E-Mail-Adresse
privateKeySecretRef: { name: letsencrypt-prod-account-key }
solvers: [{ http01: { ingress: { class: nginx } } }]
EOFDie externe Adresse für deinen DNS-Eintrag finden
Auf diese Adresse zeigt später dein domains.app-Eintrag. IP-basierte Load Balancer (GKE/k3s) füllen das Feld .ip, hostnamenbasierte (AWS NLB/ELB) das Feld .hostname. Dieser Befehl gibt aus, was vorhanden ist:
kubectl -n ingress-nginx get svc ingress-nginx-controller \
-o jsonpath='{.status.loadBalancer.ingress[0].ip}{.status.loadBalancer.ingress[0].hostname}{"\n"}'
# → eine IP → leg einen A-Record an (domains.app A <ip>)
# → ein Host → leg einen CNAME an (domains.app CNAME <host>); ein Apex-domains.app
# braucht einen Route 53 Alias / external-dns. Siehe Skalierung → "Amazon EKS".Storage-Klassen für gemanagte Kubernetes-Angebote und Provider-Spezifika findest du im Kapitel Skalierung & Betreiber. Die gesamte folgende Routine ist idempotent -- du kannst sie nach dem Korrigieren eines Werts gefahrlos erneut ausführen.
Installation mit install.sh
Aus deinem Welcome-Pack brauchst du zwei Dinge: die Lizenzdatei und die Registry-Zugangsdaten (zum Ziehen der Images).
# aus deinem Welcome-Pack: Lizenzdatei + Registry-Zugangsdaten
./install.shDas Skript fragt interaktiv nach App-Domain, Lizenzpfad, Registry-Zugangsdaten, der zu installierenden Chart-Version und optional nach SMTP. Es macht dann Folgendes:
- Preflight -- prüft, ob
kubectl,helm(3.10+) undopensslvorhanden und der Cluster erreichbar ist. - Legt den Namespace und die Secrets an -- die Lizenz (
hoppla-license), das Registry-Pull-Secret (hoppla-registry) und das Anwendungs-Secret (hoppla-secrets, in demAPP_KEYund die Reverb-Schlüssel für dich generiert werden). - Installiert das Chart mit dem Small-Profil und deiner Domain.
- Nennt dir die zwei Abschlussbefehle, die das Setup vervollständigen.
Alles, was das Skript tut, ist reines kubectl/helm -- lies es ruhig durch. Mehrfaches Ausführen ist sicher: vorhandene Secrets bleiben unangetastet (lösche sie zuerst, wenn du sie neu generieren willst), und hoppla:install verweigert die Arbeit auf einer bereits installierten Instanz.
Die zwei Abschlussbefehle
Nach der Installation führst du diese beiden Artisan-Befehle im API-Pod aus (beide idempotent):
# 1. legt die Instanz und ihren ersten Admin an (No-op auf einer bereits installierten Instanz)
kubectl -n hoppla exec -it deploy/hoppla-api -c api -- php artisan hoppla:install
# 2. prüft DB/TimescaleDB, Redis, Queues, Scheduler, SMTP, RLS und die Lizenz end-to-end
kubectl -n hoppla exec -it deploy/hoppla-api -c api -- php artisan hoppla:doctorDer Release-Fullname des API-Deployments lautet
<release>-<chart>-api(z. B.hoppla-hoppla-selfhosted-api), nicht zwangsläufighoppla-api. Wenndeploy/hoppla-apinicht aufgelöst wird, finde es per Label:kubectl -n hoppla get deploy -l app.kubernetes.io/component=api.
Danach richtest du DNS für deine domains.app auf die Adresse deines Ingress-Controllers und meldest dich an.
Manuelle Installation
Wenn du lieber direkt mit Helm arbeitest, nutzt du das OCI-Chart und ein Werte-Profil:
helm upgrade --install hoppla \
oci://ghcr.io/jkbennemann/charts/hoppla-selfhosted \
--version <CHART_VERSION> -n hoppla --create-namespace \
-f values.self-hosted-small.yaml \
--set domains.app=monitoring.example.com \
--set existingSecret=hoppla-secrets \
--set license.secretName=hoppla-licenseDie einzige Pflichtangabe ist domains.app. Daraus leitet das Chart alle ineinandergreifenden Domain-Einstellungen ab (Session-Scope, CORS, CNAME-Ziele). Die Domains für White-Label-Portale und Status Pages kommen aus domains.portalRoot bzw. domains.statusRoot -- siehe Konfiguration.
Die Secrets hoppla-license und hoppla-secrets musst du beim manuellen Weg selbst anlegen (das install.sh nimmt dir das ab). Wie sie aufgebaut sind, steht in der Konfiguration → Secrets.
Es gibt vier Werte-Profile (small/medium/large/probe). Welches für dich passt, klärt das Kapitel Skalierung & Betreiber → Profil wählen. Lege pro Cluster genau eine Kopie deines Profils unter Versionskontrolle und übergib sie immer mit
-f-- nie--reuse-values.
Die App über HTTPS bereitstellen
domains.app konfiguriert URLs und CORS, erstellt aber nicht von sich aus einen Ingress (ingress.enabled ist standardmäßig false, ab Werk ist die App also nur per kubectl port-forward erreichbar). Um sie unter deiner Domain mit einem cert-manager-TLS-Zertifikat auszuliefern, fügst du ein Ingress-Override hinzu und übergibst es dem Installer (HELM_EXTRA_ARGS="-f ingress.yaml" ./install.sh, oder deinem eigenen helm upgrade):
# ingress.yaml
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
tls:
- secretName: hoppla-app-tls
hosts: [monitoring.example.com] # = deine domains.app
hosts:
- host: monitoring.example.com # = deine domains.app
paths:
- { path: /api, service: api }
- { path: /sanctum, service: api }
- { path: /ping, service: api }
- { path: /app, service: reverb }
- { path: /, service: dashboard }Richte dann DNS für domains.app auf die externe Adresse von ingress-nginx aus dem Voraussetzungs-Schritt (A-Record auf eine IP, oder CNAME auf den LB-Hostnamen bei AWS -- siehe Skalierung & Betreiber). Das Zertifikat wird automatisch ausgestellt, sobald DNS auflöst.
E-Mail (SMTP)
Benachrichtigungen, Einladungen und Reports brauchen einen echten Mailer. Du konfigurierst ihn bei der Installation (install.sh fragt nach SMTP) oder später, indem du das Secret bearbeitest.
Diese Schlüssel liegen auf hoppla-secrets (MAIL_MAILER=smtp, MAIL_HOST, MAIL_PORT, MAIL_USERNAME, MAIL_PASSWORD, MAIL_ENCRYPTION, MAIL_FROM_ADDRESS). Beispiel für Mailgun (EU):
kubectl -n hoppla patch secret hoppla-secrets --type merge -p '{"stringData":{
"MAIL_MAILER":"smtp",
"MAIL_HOST":"smtp.eu.mailgun.org",
"MAIL_PORT":"587",
"MAIL_USERNAME":"[email protected]",
"MAIL_PASSWORD":"<mailgun smtp password>",
"MAIL_ENCRYPTION":"",
"MAIL_FROM_ADDRESS":"[email protected]"
}}'
# Pods lesen das Secret beim Start — roll sie ALLE neu, damit der neue Mailer greift.
kubectl -n hoppla rollout restart deployWichtig
Benachrichtigungen werden von den Worker-Pods verschickt, nicht vom API-Pod. Starte bei einem Mailer-Wechsel jedes Deployment neu (rollout restart deploy), nicht nur die API -- sonst geht der --send-test unten durch (er läuft im API-Pod), während echte Benachrichtigungen weiter das veraltete Secret verwenden.
Port 465 = implizites TLS (MAIL_ENCRYPTION=tls); 587/2525/25 verwenden STARTTLS (MAIL_ENCRYPTION leer lassen). Zustellbarkeit prüfen:
kubectl -n hoppla exec deploy/hoppla-api -c api -- \
php artisan hoppla:doctor [email protected]hoppla:doctor warnt auch, wenn der SMTP-Host nicht gesetzt oder nicht erreichbar ist. Reseller können zusätzlich aus ihrer eigenen Domain senden (Per-Tenant-SMTP) -- siehe White-Label & Reseller.