NGINX vs. Caddy: Ein ehrlicher Stabilitätsvergleich für Ghost und ActivityPub
Wer seinen Ghost-Blog mit ActivityPub-Unterstützung betreibt, steht früher oder später vor einer Grundsatzentscheidung: Welchen Reverse Proxy setze ich ein? Caddy gilt als modern, entwicklerfreundlich und wirbt mit automatischem HTTPS – klingt verlockend. NGINX hingegen ist alt, kampferprobt und manchmal sperrig in der Konfiguration. Doch was passiert, wenn man beide im echten Betrieb vergleicht – speziell im Zusammenhang mit dem ActivityPub-Protokoll und Ghost?
Dieser Artikel ist kein Marketing-Vergleich auf Basis von Benchmark-Tabellen. Es ist ein Erfahrungsbericht aus dem produktiven Betrieb, ergänzt um technische Hintergründe, die erklären, warum sich beide Proxys bei ActivityPub so unterschiedlich verhalten.
Kurz zur Ausgangslage: Ghost und ActivityPub
Ghost unterstützt seit Version 5.x das ActivityPub-Protokoll – das dezentrale Kommunikationsprotokoll hinter Mastodon, Lemmy und dem sogenannten Fediverse. Über ActivityPub können Ghost-Blogs mit Mastodon-Instanzen interagieren: Artikel werden als Notizen verteilt, Antworten kommen zurück, Follows werden synchronisiert.
Das klingt simpel, ist es aber nicht. ActivityPub ist ein HTTP-basiertes Protokoll mit sehr spezifischen Anforderungen:
- Signierte HTTP-Requests (HTTP Signatures): Jede Aktivität wird vom sendenden Server signiert. Der empfangende Server validiert diese Signatur gegen den öffentlichen Schlüssel, der im
/.well-known/webfinger- und ActivityPub-Actor-Endpoint liegt. - Strikte Header-Anforderungen:
Content-Type: application/activity+jsonmuss korrekt weitergeleitet werden. Manipulationen oder fehlende Header führen zu stillschweigenden Fehlern. - Zeitkritische Verarbeitung: HTTP-Signaturen haben ein kurzes Ablaufzeitfenster (oft 60 Sekunden). Verzögerungen, Queues oder Caching können dazu führen, dass Signaturen beim Empfänger bereits abgelaufen sind.
- WebFinger-Endpoint:
/.well-known/webfingermuss korrekt geroutet werden – fehlerhafte Weiterleitungen oder Header-Manipulationen brechen die Actor-Discovery.
Wer also einen Reverse Proxy vor Ghost schaltet, der auch nur in einem dieser Punkte unzuverlässig agiert, wird früher oder später Probleme mit der Föderation erleben.
NGINX: Der verlässliche Veteran
NGINX existiert seit 2004. Es ist stabiler Bestandteil von Produktionsumgebungen weltweit – von kleinen Blogs bis zu Netflix. Die Konfiguration ist deklarativ, gut dokumentiert und seit Jahren unverändert zuverlässig.
Was NGINX richtig macht
Transparente Header-Weiterleitung: In einer typischen Ghost-Konfiguration mit NGINX werden alle Header explizit durchgereicht:
location / {
proxy_pass http://localhost:2368;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
Was man nicht konfiguriert, wird nicht verändert. NGINX ist in diesem Sinne ein ehrlicher Durchleiter: kein heimliches Caching, keine automatischen Header-Transformationen, die man nicht explizit angeordnet hat.
Stabiles Prozessmodell: NGINX verwendet einen Master-Prozess mit Worker-Prozessen. Konfigurationsänderungen werden mit nginx -s reload graceful neu geladen – laufende Verbindungen bleiben bestehen. Es gibt keinen automatischen Neustart im Hintergrund, keine automatischen Zertifikatserneuerungen, die den Proxy kurzzeitig in einen undefinierten Zustand bringen könnten.
Vorhersehbares TLS-Verhalten: Zusammen mit Certbot (Let's Encrypt) ist TLS in NGINX ein gelöstes Problem. Zertifikatserneuerung läuft per Cron oder systemd-Timer, ist entkoppelt vom Proxy-Betrieb und produziert keine unerwarteten Nebeneffekte.
Kein automatisches State-Management: NGINX speichert keinen internen Zustand über den laufenden Betrieb hinaus. Es gibt keine Datenbank, keinen eingebetteten ACME-Client, der im Hintergrund Zertifikate verwaltet und dabei möglicherweise Verbindungen unterbricht.
Caddy: Modern, aber komplex unter der Haube
Caddy ist seit Version 2 ein leistungsfähiger Reverse Proxy mit eingebautem ACME-Client (automatisches HTTPS über Let's Encrypt oder ZeroSSL), einer API-Schnittstelle für dynamische Konfiguration und einer deutlich benutzerfreundlicheren Konfigurationssprache (Caddyfile).
Was Caddy gut macht
- Automatisches HTTPS ohne externe Tools – ideal für einfache Setups
- Übersichtliche Konfigurationssyntax
- Eingebaute HTTP/2- und HTTP/3-Unterstützung
- Dynamische Konfiguration via Admin-API ohne Neustart
Wo Caddy bei ActivityPub ins Straucheln gerät
Hier wird es interessant – und für Ghost-Betreiber relevant.
1. Automatische Header-Modifikation
Caddy kann unter bestimmten Umständen Header automatisch modifizieren oder ergänzen. Insbesondere der Content-Type-Header ist ein bekanntes Problemfeld: Wenn Caddy entscheidet, Responses zu puffern oder zu verändern, kann der application/activity+json-Content-Type verloren gehen oder durch einen generischen application/json ersetzt werden. Empfangende ActivityPub-Instanzen interpretieren dann die Aktivität möglicherweise falsch oder lehnen sie stillschweigend ab.
2. Zertifikatsmanagement und transiente Ausfälle
Caddys eingebauter ACME-Client ist komfortabel, aber er läuft innerhalb des Proxy-Prozesses. Bei der Zertifikatserneuerung – die automatisch und ohne manuelle Intervention erfolgt – gibt es kurze Zeitfenster, in denen Caddy intern in einem Übergangszustand ist. In dieser Phase können eingehende Requests verzögert oder mit unerwarteten Antworten beantwortet werden.
Für normale Web-Requests ist das unproblematisch: Ein Browser wartet kurz, lädt neu. ActivityPub-Anfragen von Mastodon-Instanzen hingegen haben strikte Timeouts. Wenn ein eingehender Activity-POST zu lange wartet oder eine fehlerhafte Antwort erhält, wird er nicht wiederholt – die Aktivität geht verloren.
3. Das Caching-Problem
Caddy kann bei bestimmten Konfigurationen (insbesondere in Kombination mit Plugins) aggressiv cachen. Der /.well-known/webfinger-Endpoint darf jedoch nicht gecacht werden: Wenn ein Mastodon-Server den Actor-Schlüssel eines Ghost-Blogs abruft und eine gecachte, veraltete Version erhält, schlägt die Signaturvalidierung fehl. Die Folge ist keine Fehlermeldung – die Aktivitäten werden einfach nicht mehr verarbeitet.
4. Intermittierende Föderationsprobleme: das eigentliche Symptom
Das typische Fehlerbild sieht so aus: Ghost föderiert problemlos über Wochen. Dann – ohne erkennbaren Auslöser – stoppt die Föderation. Neue Posts erscheinen nicht mehr auf verbundenen Mastodon-Instanzen, Follows werden nicht synchronisiert. Ein Neustart von Caddy behebt das Problem vorübergehend. Nach einiger Zeit tritt es erneut auf.
Was passiert im Hintergrund? Wahrscheinlich ein Zusammenspiel mehrerer Faktoren:
- Caddy hat intern seinen Zustand (Zertifikat, Routing-Konfiguration, HTTP/2-Sessions) neu aufgebaut
- Dabei wurden aktive Verbindungen oder Queues unterbrochen
- Ghost hat seinerseits einen Retry-Mechanismus, der nach mehreren Fehlversuchen aufgibt
- Das Fediverse auf der Gegenseite markiert den Server als temporär nicht erreichbar und versucht es nicht mehr
Bis man das bemerkt, sind Tage vergangen.
Der direkte Vergleich
| Kriterium | NGINX | Caddy |
|---|---|---|
| Stabilität im Dauerbetrieb | ✅ Sehr hoch | ⚠️ Gut, aber mit gelegentlichen Transients |
| Header-Transparenz | ✅ Vollständig kontrollierbar | ⚠️ Teilweise automatische Modifikationen |
| ActivityPub-Kompatibilität | ✅ Zuverlässig | ⚠️ Abhängig von Konfiguration |
| TLS-Management | ⚠️ Extern via Certbot | ✅ Eingebaut und automatisch |
| Konfigurationskomplexität | ⚠️ Höher, aber vorhersehbar | ✅ Einfacher |
| Debugging | ✅ Ausführliche Logs, bekannte Toolchain | ⚠️ Interner Zustand schwerer einsehbar |
| Graceful Reload | ✅ Ja | ✅ Ja |
| HTTP/3 Support | ⚠️ Experimentell (nginx 1.25+) | ✅ Nativ |
| Vorhersehbarkeit | ✅ Sehr hoch | ⚠️ Mittel |
Empfehlung für Ghost mit ActivityPub
Wenn du Ghost mit Fediverse-Unterstützung betreibst und Wert auf zuverlässige, dauerhafte Föderation legst: Verwende NGINX.
Nicht weil Caddy ein schlechter Proxy wäre. Caddy ist für viele Anwendungsfälle hervorragend geeignet. Aber ActivityPub ist ein Protokoll, das auf strikter HTTP-Konformität, zuverlässiger Header-Weiterleitung und stabilen Verbindungen basiert. NGINX liefert genau das – ohne Überraschungen, ohne internen Zustand, der im Hintergrund kippt.
Minimale NGINX-Konfiguration für Ghost mit ActivityPub
server {
listen 443 ssl http2;
server_name deinblog.de;
ssl_certificate /etc/letsencrypt/live/deinblog.de/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/deinblog.de/privkey.pem;
# ActivityPub-spezifisch: keine Pufferung für Activity-Endpoints
location ~* ^/(\.well-known|activitypub|ghost/activitypub) {
proxy_pass http://localhost:2368;
proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 30s;
}
location / {
proxy_pass http://localhost:2368;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Real-IP $remote_addr;
}
}
Der entscheidende Punkt: proxy_buffering off für ActivityPub-Endpoints verhindert, dass NGINX Responses puffert und dabei Headers verändert. proxy_read_timeout stellt sicher, dass Ghost genug Zeit hat, Aktivitäten zu verarbeiten, ohne dass NGINX die Verbindung vorzeitig schließt.
Fazit
Caddy ist ein exzellenter Proxy für viele Szenarien – einfache Web-Apps, schnelle Deployments, Situationen, in denen automatisches HTTPS ein echter Mehrwert ist. Für ActivityPub-basierte Anwendungen wie Ghost ist der interne Komplexität von Caddy jedoch ein Risikofaktor.
NGINX ist nicht sexy. Die Konfiguration ist wortreich, Certbot muss separat verwaltet werden, und HTTP/3 ist noch nicht produktionsreif. Aber NGINX tut genau das, was man ihm sagt – nicht mehr, nicht weniger. Für ein Protokoll wie ActivityPub, das auf Vorhersehbarkeit und HTTP-Konformität angewiesen ist, ist das eine Tugend, keine Schwäche.
Wenn deine Ghost-Instanz plötzlich aufhört zu föderieren, ist dein Reverse Proxy der erste Ort, den du untersuchen solltest.
Dieser Artikel basiert auf praktischen Erfahrungen im Betrieb von Ghost mit ActivityPub-Unterstützung sowie auf einer Analyse der Protokollspezifikationen von ActivityPub (W3C) und den jeweiligen Proxy-Dokumentationen.