Skip to content

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.

bash
# 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 } } }]
EOF

Die 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:

bash
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).

bash
# aus deinem Welcome-Pack: Lizenzdatei + Registry-Zugangsdaten
./install.sh

Das Skript fragt interaktiv nach App-Domain, Lizenzpfad, Registry-Zugangsdaten, der zu installierenden Chart-Version und optional nach SMTP. Es macht dann Folgendes:

  1. Preflight -- prüft, ob kubectl, helm (3.10+) und openssl vorhanden und der Cluster erreichbar ist.
  2. Legt den Namespace und die Secrets an -- die Lizenz (hoppla-license), das Registry-Pull-Secret (hoppla-registry) und das Anwendungs-Secret (hoppla-secrets, in dem APP_KEY und die Reverb-Schlüssel für dich generiert werden).
  3. Installiert das Chart mit dem Small-Profil und deiner Domain.
  4. 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):

bash
# 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:doctor

Der Release-Fullname des API-Deployments lautet <release>-<chart>-api (z. B. hoppla-hoppla-selfhosted-api), nicht zwangsläufig hoppla-api. Wenn deploy/hoppla-api nicht 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:

bash
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-license

Die 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):

yaml
# 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):

bash
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 deploy

Wichtig

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:

bash
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.