HTTP-Caching für eine persönliche Website — Aktuelle Seiten und schnelle Assets
Eine persönliche Website kann sich beim zweiten Besuch aus einem einfachen Grund schnell anfühlen: Der Browser hat möglicherweise bereits einige ihrer Dateien gespeichert. Derselbe Mechanismus kann jedoch auch ein altes Stylesheet weiterverwenden, das HTML von gestern anzeigen oder eine personalisierte Antwort an einem Ort ablegen, an dem ein gemeinsam genutzter Cache sie wiederverwenden kann. Die entscheidende Frage lautet deshalb nicht: „Sollte diese Website Caching verwenden?“, sondern: „Welche Antworten dürfen von wem und wie lange wiederverwendet werden?“
HTTP verfügt bereits über ein Vokabular, um diese Frage zu beantworten. Für eine praktikable Richtlinie muss man nicht jede Direktive auswendig lernen. Man muss jedoch Frische und Validierung voneinander trennen, den missverständlichen Namen no-cache richtig einordnen und eine URL als Versprechen darüber behandeln, wie sich ihr Inhalt verändert.
Was ein HTTP-Cache tatsächlich tut
RFC 9111 definiert einen Cache als lokalen Speicher für Antwortnachrichten zusammen mit dem Subsystem, das deren Speicherung, Abruf und Löschung steuert. Die Wiederverwendung einer geeigneten Antwort kann die Antwortzeit verkürzen und verhindern, dass dieselben Bytes erneut übertragen werden. Außerdem muss der Origin einen weiteren gleichwertigen Request nicht erneut verarbeiten.
Dabei sind zwei Grenzen zu beachten. Ein privater Cache ist einem einzelnen Benutzer zugeordnet und befindet sich häufig im Browser. Ein gemeinsam genutzter Cache kann eine Antwort für mehrere Benutzer wiederverwenden; Reverse-Proxys und CDNs sind bekannte Beispiele. Eine Antwort, die im Browser einer Person sicher ist, ist nicht automatisch auch in einem gemeinsam genutzten Cache sicher.
Eine gespeicherte Antwort ist frisch, solange ihr Alter innerhalb ihrer Frischelebensdauer liegt. Eine frische Antwort kann normalerweise wiederverwendet werden, ohne den Origin zu kontaktieren. Sobald sie veraltet ist, wird sie nicht zwingend verworfen. Der Cache kann beim Origin nachfragen, ob seine Kopie noch gültig ist. RFC 9111 bezeichnet diesen Vorgang als Validierung oder Revalidierung.
Diese Unterscheidung ist wichtig, weil Caching auf zwei verschiedene Arten Arbeit einsparen kann:
- Frische kann einen Netzwerk-Request für einen bestimmten Zeitraum vollständig vermeiden.
- Validierung kontaktiert den Server weiterhin, kann aber die erneute Übertragung des Antwortinhalts vermeiden, wenn sich nichts geändert hat.
Frische und Validierung sind unterschiedliche Steuerungen
Die Response-Direktive max-age legt eine explizite Frischelebensdauer in Sekunden fest. Die folgende Antwort kann beispielsweise eine Stunde lang frisch bleiben:
Cache-Control: max-age=3600
Das garantiert nicht, dass jeder Cache die Antwort speichert. HTTP-Caching ist optional, und Implementierungen können lokale Speicher- und Verdrängungsrichtlinien anwenden. Der Header beschreibt, wann eine gespeicherte Antwort wiederverwendet werden darf; er ist kein Befehl, Speicherplatz zu reservieren.
Die Validierung verwendet Metadaten, die eine Repräsentation identifizieren. Ein Origin kann einen ETag, ein Last-Modified-Datum oder beides senden. Später kann ein Client diese Metadaten in If-None-Match oder If-Modified-Since zurücksenden. Wenn sich die ausgewählte Repräsentation nicht geändert hat, kann der Server mit 304 Not Modified und ohne Nachrichteninhalt antworten. Die genauen Semantiken von Validatoren und bedingten Requests stehen in RFC 9110. Wenn beide relevanten Request-Bedingungen vorhanden sind, hat If-None-Match Vorrang vor If-Modified-Since.
Ein Validator ist keine Frischelebensdauer. Er gibt dem Cache eine günstigere Frage, die er stellen kann, wenn eine Antwort überprüft werden muss. Umgekehrt kann ein langes max-age diese Frage unterdrücken, bis die Antwort veraltet ist. Gute Richtlinien verwenden oft beide Mechanismen, jedoch für unterschiedliche Aufgaben.
Die Direktive mit dem missverständlichsten Namen
Cache-Control: no-cache bedeutet nicht „nicht speichern“. Es bedeutet, dass eine gespeicherte Antwort nicht ohne erfolgreiche Validierung wiederverwendet werden darf. Das ist für eine stabile Seiten-URL nützlich, deren Inhalt sich ändern kann: Der Cache darf eine Kopie behalten, aber der Origin kann sie vor der Wiederverwendung bestätigen.
Cache-Control: no-cache
ETag: "page-revision-42"
Cache-Control: no-store ist die Direktive, die Caches anweist, die Antwort nicht zu speichern. Sie ist geeignet, wenn schon das Aufbewahren der Antwort nicht akzeptabel ist. Eine pauschale Verwendung verzichtet allerdings auf nützliches Browserverhalten und eingesparte Übertragungen. Die Direktive löscht außerdem nicht rückwirkend eine ältere, bereits unter derselben URL gespeicherte Antwort. Die praktischen Unterschiede und Abwägungen erläutert der MDN-Leitfaden zu HTTP-Caching.
private beantwortet eine andere Frage. Die Direktive verhindert, dass ein gemeinsam genutzter Cache die vollständige Antwort speichert, erlaubt aber weiterhin die Speicherung in einem privaten Cache. Eine personalisierte Kontoseite könnte daher Folgendes verwenden:
Cache-Control: private, no-cache
Das ist ein vernünftiger Ausgangspunkt, keine universelle Antwort. Für eine Antwort mit besonders sensiblen Informationen kann no-store angemessen sein. Ein öffentlicher Artikel wird auch nicht allein deshalb privat, weil ein Besucher ein Cookie besitzt. Die Richtlinie sollte dem tatsächlichen Inhalt der Antwort und ihrer Datenschutzgrenze folgen, nicht einer unbestimmten Angst vor Caching.
Eine kleine Richtlinie für drei Ressourcentypen
Caching lässt sich leichter beurteilen, wenn Ressourcen danach gruppiert werden, wie sie sich verändern. Für ein kleines CMS oder eine persönliche Website decken drei Gruppen einen großen Teil der Oberfläche ab.
1. Öffentliches HTML mit stabiler URL
Eine Artikel-URL sollte den Artikel auch nach einer Bearbeitung weiterhin identifizieren. Eine sehr lange Frischelebensdauer für das HTML bedeutet, dass der Origin die zwischengespeicherte Kopie bis zum Ablauf dieser Zeit nicht korrigieren kann, sofern ein verwalteter Cache keinen separaten Purge-Mechanismus bietet. Eine konservative Richtlinie lautet:
Cache-Control: no-cache
ETag: "article-252-revision-3"
Last-Modified: Sat, 22 Aug 2026 17:16:09 GMT
Diese Werte dienen nur als Beispiel; sie sind keine auf dieser Website beobachteten Header. In einem realen CMS müssen sich Validatoren ändern, wenn sich die ausgewählte Repräsentation ändert. Einen ETag aus einer verlässlichen Inhaltsrevision zu erzeugen, kann günstiger sein, als bei jedem Request die vollständig gerenderte Antwort zu hashen. Die passende Implementierung hängt jedoch von Templates, Lokalisierung, Komprimierung und weiteren Repräsentationsentscheidungen ab.
2. Versionierte statische Assets
Ein Stylesheet namens app.css kann sich verändern und dieselbe URL behalten. Eine Datei namens app.a81c9e.css kann dagegen bei jeder Inhaltsänderung eine neue URL erhalten. Weil der Cache-Schlüssel mindestens die Request-Methode und den Ziel-URI enthält, erzeugt der neue Dateiname einen neuen Lookup, statt mit den alten Bytes zu konkurrieren.
Cache-Control: public, max-age=2592000, immutable
Dreißig Tage sind hier ein Beispiel, keine magische Zahl. Entscheidend ist die stärkere Bedingung: Eine als immutable markierte URL sollte später keinen anderen Inhalt ausliefern. Wenn der Deployment-Prozess Dateien an Ort und Stelle überschreibt, sollte immutable entfallen und eine kürzere Lebensdauer gewählt werden. Langlebiges Caching funktioniert, weil versionierte URLs Änderungen ausdrücklich sichtbar machen, nicht weil eine bestimmte Dauer überall optimal wäre.
3. Personalisierte oder sensible Antworten
Seiten, die sich je nach authentifiziertem Benutzer unterscheiden, sollten nicht zur allgemeinen Wiederverwendung durch einen gemeinsam genutzten Cache verfügbar sein. private, no-cache kann die Validierung im privaten Browser-Cache erhalten. no-store kann die strengere Wahl sein, wenn bereits die Speicherung problematisch ist. RFC 9111 enthält außerdem besondere Regeln für das gemeinsame Caching authentifizierter Antworten. Authentifizierte Inhalte öffentlich cachebar zu machen, sollte daher eine bewusste Entscheidung mit eindeutigem Cache-Schlüssel sein und nicht das Ergebnis eines versehentlich von statischen Assets geerbten Headers.
Vary gehört zur Korrektheit und ist keine Dekoration
Eine URL reicht nicht immer zur Auswahl einer Repräsentation. Dieselbe URL kann abhängig von Accept-Encoding gzip- oder Brotli-Inhalte oder abhängig von Accept-Language Inhalte in verschiedenen Sprachen liefern. Das Response-Feld Vary teilt Caches mit, welche Request-Felder übereinstimmen müssen, bevor eine gespeicherte Antwort wiederverwendet werden darf.
Vary: Accept-Encoding
Ohne das passende Vary kann ein Cache die falsche Repräsentation auswählen. Das Variieren nach einem Feld mit sehr vielen möglichen Werten kann den Cache jedoch fragmentieren und die Wiederverwendung verringern. MDN warnt ausdrücklich davor, unbedacht nach User-Agent zu variieren; Feature Detection oder stabile URLs sind oft sauberer. Eine mehrsprachige Website kann die Sprachaushandlung auch vollständig vermeiden, indem jede Übersetzung eine eigene URL erhält, und dennoch nach Encoding variieren, wenn der Server Antworten dynamisch komprimiert.
Ein konservativer Ausgangspunkt für NGINX
NGINX kann mit add_header Response-Felder ergänzen. Das folgende Beispiel setzt voraus, dass Dateien unter /static/ versionierte Namen tragen und öffentliches HTML von der allgemeinen Location verarbeitet wird:
location /static/ {
add_header Cache-Control "public, max-age=2592000, immutable" always;
}
location / {
add_header Cache-Control "no-cache" always;
try_files $uri $uri/ /index.php?$query_string;
}
Das ist kein Versprechen für eine sofort einsetzbare Konfiguration. Die offizielle Dokumentation des NGINX-Headers-Moduls weist darauf hin, dass add_header-Direktiven nur dann von der vorherigen Konfigurationsebene geerbt werden, wenn auf der aktuellen Ebene keine eigenen add_header-Direktiven definiert sind. Der Parameter always verändert außerdem die standardmäßige Beschränkung auf bestimmte Statuscodes. Eine verschachtelte Location, ein PHP-Handler oder ein von der Anwendung erzeugtes Cache-Control-Feld kann das Ergebnis deshalb verändern oder duplizieren.
Für jede Richtlinie sollte eine maßgebliche Ebene gewählt, die vollständig gerenderte NGINX-Konfiguration geprüft und die tatsächlichen Routen getestet werden. Insbesondere darf die Richtlinie für statische Assets nicht auf Benutzer-Uploads oder Asset-URLs angewendet werden, die ohne Namensänderung überschrieben werden können.
Verhalten prüfen, statt der Konfigurationsdatei zu vertrauen
Ein Header in einer Konfigurationsdatei ist zunächst nur eine Absicht. Die Origin-Antwort sollte für repräsentatives HTML, Assets, Fehlerseiten und authentifizierte Routen untersucht werden:
curl -sSI https://example.com/article/
curl -sSI https://example.com/static/app.a81c9e.css
Dabei sind Cache-Control, ETag, Last-Modified, Vary und bei einem gemeinsam genutzten Cache auch Age relevant. Anschließend kann ein tatsächlicher Validator aus der ersten Antwort für einen bedingten Request verwendet werden:
curl -sSI \
-H 'If-None-Match: "validator-from-the-response"' \
https://example.com/article/
Ein 304 ist nur zu erwarten, wenn der Validator noch übereinstimmt und die Route diese Bedingung implementiert. Wenn sich der Inhalt geändert hat, ist eine vollständige Antwort korrekt. Auch nach einem Deployment sollte getestet werden: Das HTML muss auf die neue versionierte Asset-URL verweisen, und die alte versionierte URL muss ihre ursprünglichen Bytes so lange ausliefern, wie Clients sie noch cachen dürfen.
Was diese Richtlinie nicht löst
HTTP-Header können nicht jeden Browser oder Vermittler aktiv leeren, der bereits eine frische Antwort besitzt. Verwaltete CDNs können Purge-Funktionen anbieten, doch dabei handelt es sich um produktspezifische Vorgänge außerhalb des standardisierten Caching-Modells. Service Worker ergänzen einen weiteren programmierbaren Cache mit eigenem Lebenszyklus. Keiner dieser Mechanismen sollte ohne separate Tests in eine anfängliche Richtlinie gemischt werden.
Caching repariert auch keinen instabilen Deployment-Prozess. Lange Lebensdauern vergrößern die Folgen eines Fehlers, wenn eine vermeintlich unveränderliche URL überschrieben wird. Validatoren werden unzuverlässig, wenn sie nicht jede Änderung einer Repräsentation berücksichtigen. Zu breite Vary-Felder können Speicher verschwenden, während fehlende Felder falsche Inhalte ausliefern können. Das sind Gründe für eine schrittweise Einführung nach Ressourcenklasse und für Beobachtung, nicht für das pauschale Abschalten von Caching.
Fazit
Eine solide Caching-Richtlinie beginnt beim Änderungsmodell einer Ressource und ihrer Datenschutzgrenze. Öffentliches HTML mit stabiler URL kann gespeichert, aber revalidiert werden. Wirklich versionierte Assets können deutlich länger frisch bleiben. Personalisierte Antworten brauchen eine private Grenze, und sensible Antworten dürfen möglicherweise überhaupt nicht gespeichert werden. Validatoren sparen die Übertragung von Inhalten; Frische kann den Request selbst einsparen; Vary bindet die Wiederverwendung an die richtige Repräsentation.
Ein vorsichtiger Ansatz sucht nicht nach dem längstmöglichen max-age. Er macht jede URL zu einem ehrlichen Versprechen, legt Regeln ausdrücklich fest und prüft die Antworten, die Benutzer und Vermittler tatsächlich erhalten.
References
- RFC 9111: HTTP Caching — RFC Editor / IETF, June 2022.
- RFC 9110: HTTP Semantics — RFC Editor / IETF, June 2022.
- HTTP caching — MDN Web Docs, last modified August 14, 2026.
- Module ngx_http_headers_module — NGINX official documentation.
