Technik · 11 Min. Lesezeit

Cache-Control richtig setzen: Browser-Caching für Websites

Kurz erklärt

Der Header Cache-Control legt fest, ob und wie lange Browser, CDNs und Proxys eine Antwort zwischenspeichern dürfen. Richtig gesetzt, lädt eine Seite wiederkehrenden Besuchern schneller und entlastet den Server; falsch gesetzt, zeigt sie veraltete Inhalte oder lädt jede Datei bei jedem Aufruf neu. Bewährt: Dateien mit Versionsnamen lange cachen, HTML kurz oder mit Revalidierung.

Das Wichtigste in Kürze

  • max-age gibt die Frische in Sekunden an; no-cache heißt „vor Nutzung beim Server nachfragen“, nicht „nicht speichern“, das leistet no-store.
  • Statische Dateien mit Hash oder Version im Namen cachen Sie ein Jahr lang (max-age=31536000, immutable); HTML bleibt kurz oder revalidiert.
  • ETag und Last-Modified ermöglichen billige Nachfragen: Der Server antwortet mit 304 Not Modified ohne Inhalt.
  • Fehlt Cache-Control, rät der Browser anhand von Heuristiken, das ist selten, was Sie wollen.
  • Personalisierte Seiten (Warenkorb, Konto) gehören mit private oder no-store markiert, sonst droht Auslieferung fremder Inhalte durch Shared Caches.

Was macht Cache-Control und warum ist es relevant?

Jede Datei, die ein Besucher lädt, durchläuft potenziell mehrere Zwischenspeicher: den Browser-Cache, einen Proxy des Unternehmens, ein CDN. Der Header Cache-Control ist die Anweisung des Servers, wie diese Speicher mit der Antwort umgehen sollen. Der Standard dazu ist RFC 9111 (HTTP Caching); eine gut lesbare Einführung bietet MDN (beides in den Quellen).

Warum lohnt sich ein genauer Blick? Aus drei Gründen. Erstens Geschwindigkeit: Eine Datei aus dem Cache kostet keine Netzwerkanfrage, Wiederholungsbesucher sehen die Seite spürbar schneller; das beeinflusst auch Messgrößen wie die Core Web Vitals (siehe web.dev in den Quellen) und die gefühlte Antwortzeit. Zweitens Serverlast: Jede aus dem Cache bediente Anfrage erreicht den Server nicht. Drittens Korrektheit: Zu lange gespeicherte Inhalte zeigen nach einem Update die alte Version, und fehlerhaft gecachte, personalisierte Seiten können Datenschutzprobleme auslösen.

Welche Direktiven gibt es und was bedeuten sie?

DirektiveBedeutungTypischer Einsatz
max-age=NAntwort gilt N Sekunden als frisch; in dieser Zeit ohne Rückfrage nutzbarStatische Dateien, kurz gecachtes HTML
s-maxage=NWie max-age, aber nur für Shared Caches (CDN, Proxy); hat dort VorrangCDN länger cachen lassen als den Browser
no-cacheDarf gespeichert werden, muss aber vor jeder Nutzung beim Server revalidiert werdenHTML, das immer aktuell sein soll, aber 304-fähig bleibt
no-storeNicht speichern, nirgendwoSensible Inhalte (Solo, Zahlungsdaten)
publicAuch Shared Caches dürfen speichern, selbst wenn es sonst nicht der Fall wäre (z. B. bei Autorisierung)Selten nötig, bei CDN-Assets
privateNur der Browser des Nutzers darf speichern, keine Shared CachesPersonalisierte Seiten
immutableInhalt ändert sich während der Frische nie; Browser fragen auch beim Neuladen nicht nachDateien mit Hash im Namen
must-revalidateNach Ablauf der Frische nicht ohne Rückfrage nutzen, auch nicht bei ServerfehlerWenn veraltete Inhalte inakzeptabel sind
stale-while-revalidate=NAbgelaufene Antwort darf N Sekunden weiter ausgeliefert werden, während im Hintergrund neu geladen wirdSchnell wirkende Seiten mit leichter Unschärfe
stale-if-error=NBei Fehlern des Ursprungsservers darf eine alte Antwort N Sekunden ausgeliefert werdenRobustheit bei Ausfällen

Die letzten beiden sind in RFC 5861 beschrieben und werden nicht von jedem Cache unterstützt; testen Sie sie in Ihrer Umgebung. immutable stammt aus RFC 8246. Direktiven lassen sich kombinieren, etwa public, max-age=600, stale-while-revalidate=60.

Zwei Missverständnisse halten sich hartnäckig. no-cache verhindert nicht das Speichern, sondern erzwingt Rückfragen; wer wirklich nichts speichern lassen will, braucht no-store. Und das veraltete Pragma: no-cache stammt aus HTTP/1.0 und ist als Antwort-Header nicht zuverlässig definiert; ein modernes Cache-Control macht es überflüssig. Der ältere Header Expires (ein absolutes Datum) wird ignoriert, sobald max-age vorhanden ist.

Wie funktioniert die Revalidierung mit ETag und Last-Modified?

Ist eine Antwort nicht mehr frisch, muss der Cache nicht alles neu laden, sondern kann fragen, ob sich etwas geändert hat. Dafür liefert der Server Validatoren mit:

  • ETag: "a1b2c3": eine Kennung der Version der Datei.
  • Last-Modified: Wed, 14 Oct 2026 08:30:00 GMT: der Zeitpunkt der letzten Änderung.

Bei der nächsten Anfrage sendet der Browser If-None-Match: "a1b2c3" beziehungsweise If-Modified-Since mit. Ist die Datei unverändert, antwortet der Server mit 304 Not Modified und ohne Inhalt; der Browser nutzt seine Kopie. Das spart Bandbreite, kostet aber weiterhin eine Anfrage (Statuscodes erklärt dieser Ratgeber). Deshalb ist max-age mit längerer Frist für unveränderliche Dateien besser als reine Revalidierung.

Ohne Cache-Control bleibt es dem Cache überlassen, wie lange er Antworten frisch hält. RFC 9111 erlaubt in diesem Fall eine heuristische Frische, die häufig als Bruchteil (oft 10 %) der Zeit seit Last-Modified berechnet wird. Eine Datei, die vor 100 Tagen zuletzt geändert wurde, könnte so rund 10 Tage lang ohne Rückfrage ausgeliefert werden. Wer das nicht will, setzt Cache-Control ausdrücklich.

Welche Cache-Strategie passt zu welchem Inhalt?

InhaltEmpfohlene EinstellungBegründung
CSS/JS/Schriften mit Hash oder Version im Dateinamen (app.3f9a1c.js)public, max-age=31536000, immutableNeue Version = neuer Name, alte Datei ändert sich nie
Bilder, die selten wechseln, mit festem Namenpublic, max-age=2592000 (30 Tage) oder kürzerAustausch ohne Namenswechsel braucht kürzere Frist
HTML-Seiten (Artikel, Landingpages)no-cache oder max-age=60..600 mit ETagInhalte ändern sich, Links auf Assets müssen aktuell sein
Startseite eines aktiven Shops oder MagazinsKurz (z. B. max-age=60) plus stale-while-revalidateBalance aus Last und Aktualität
Personalisierte Seiten (Solo, Warenkorb, Checkout)private, no-storeKeine Speicherung in Shared Caches, keine Rückgabe über „Zurück“
API-AntwortenJe nach Daten no-store oder max-age kurz mit ETagAktualität bestimmt, nicht Gewohnheit
Weiterleitungen (301)Bewusst setzen, siehe Weiterleitungen und Redirect-KettenDauerhafte Weiterleitungen werden von Browsern hartnäckig gespeichert
Beispielrechnung

Angenommen (Beispielannahme), Ihre Seite lädt pro Aufruf 1,8 MB an statischen Dateien (Skripte, Styles, Bilder, Schriften), und Sie haben 20.000 Aufrufe am Tag, davon 40 % von Wiederholungsbesuchern. Ohne Caching-Header oder mit no-cache laden diese Besucher alle Dateien jedes Mal neu oder revalidieren sie: Bei Revalidierung fallen zwar nur kleine 304-Antworten an, aber pro Datei eine Anfrage. Mit max-age=31536000, immutable für Dateien mit Hash entfällt auch das. Rechnung für die Datenmenge, wenn nichts gecacht wird: 20.000 × 1,8 MB = 36 GB pro Tag. Cachen die 8.000 Wiederholungsbesucher 90 % davon, sparen Sie 8.000 × 1,8 MB × 0,9 = 12,96 GB pro Tag, also rund 36 %. Die Zahlen sind eine Rechenillustration; Ihre Werte entnehmen Sie Ihrem Server-Log oder CDN.

Wie vermeiden Sie veraltete Dateien: Fingerprinting

Je länger Sie eine Datei cachen, desto wichtiger ist ein Weg, sie bei Änderungen zu ersetzen. Das Ziel ist, dass sich bei jeder Änderung der Dateiname ändert, damit der Browser sie als neue Ressource behandelt. Das geschieht durch einen Hash im Namen (app.3f9a1c.css) oder durch einen Versionsparameter (app.css?v=20261016). Moderne Build-Werkzeuge erzeugen Hash-Namen automatisch; bei Eigenbau genügt ein Parameter, der sich bei jedem Deployment ändert, etwa die Datei-Änderungszeit.

Wichtig ist, dass die HTML-Seite, die auf die Dateien verweist, nicht lange gecacht wird: Sie ist die Einstiegstür. Ist die Startseite einen Tag lang im Browser gespeichert, verweist sie einen Tag lang auf alte Dateinamen, die vielleicht nicht mehr existieren. Deshalb gilt die Faustregel: HTML kurz oder revalidieren, Assets mit Versionsnamen lang.

Wie setzen Sie Cache-Control in nginx und Apache?

nginx

# Statische Dateien mit Versionsname: ein Jahr, unveränderlich
location ~* \.(?:css|js|woff2|svg|webp|jpg|png)$ {
    add_header Cache-Control "public, max-age=31536000, immutable" always;
    # Achtung: add_header hier ersetzt geerbte Header des server-Blocks,
    # Security-Header ggf. wiederholen (siehe Ratgeber Security-Header).
}

# HTML: immer revalidieren
location / {
    add_header Cache-Control "no-cache" always;
    try_files $uri $uri/ /index.php?$args;
}

Alternativ erzeugt die Direktive expires 1y; sowohl Expires als auch Cache-Control: max-age=31536000. Beachten Sie, dass add_header keinen bestehenden Cache-Control-Header ersetzt, den PHP oder ein Proxy bereits gesetzt hat; es kann zu doppelten Headern kommen. Bei PHP-Anwendungen steuert oft die Anwendung selbst die Header (WordPress-Cache-Plugins, Shop-Systeme); setzen Sie dann nicht zusätzlich Regeln im Server, die dagegen arbeiten.

Apache

<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType text/css "access plus 1 year"
    ExpiresByType application/javascript "access plus 1 year"
    ExpiresByType font/woff2 "access plus 1 year"
    ExpiresByType image/webp "access plus 1 month"
</IfModule>

<IfModule mod_headers.c>
    <FilesMatch "\.(css|js|woff2)$">
        Header set Cache-Control "public, max-age=31536000, immutable"
    </FilesMatch>
    <FilesMatch "\.html$">
        Header set Cache-Control "no-cache"
    </FilesMatch>
</IfModule>

PHP (dynamische Seiten)

// Persönliche Seite: nicht in Shared Caches, nicht speichern
header('Cache-Control: private, no-store');

// Öffentliche Seite: 5 Minuten, danach im Hintergrund aktualisieren
header('Cache-Control: public, max-age=300, stale-while-revalidate=60');

PHP-Sitzungen setzen bei aktivem session_start() eigene Cache-Header (Voreinstellung session.cache_limiter = nocache); das verhindert Caching, auch wenn Sie es für öffentliche Seiten wünschen. Setzen Sie session_cache_limiter('') oder nutzen Sie Sitzungen nur dort, wo sie nötig sind.

Wie prüfen Sie Cache-Header mit curl?

# Header einer Datei ansehen
curl -sI https://www.example.de/assets/app.3f9a1c.css

# Interessante Zeilen herausfiltern
curl -sI https://www.example.de/ | grep -iE 'cache-control|etag|last-modified|expires|age|vary|set-cookie'

# Revalidierung testen: ETag aus der ersten Antwort mitsenden
curl -sI -H 'If-None-Match: "a1b2c3"' https://www.example.de/assets/app.css

Bei der letzten Abfrage sollte HTTP/1.1 304 Not Modified kommen, wenn der ETag noch passt. Weitere Hinweise liefert der Header Age: Er zeigt, wie viele Sekunden eine Antwort bereits in einem Shared Cache (CDN) liegt. Die Header X-Cache oder CF-Cache-Status variieren je nach Anbieter und zeigen, ob ein Treffer vorlag. Prüfen Sie auch im Browser: In den Entwicklertools (Netzwerk) steht bei zwischengespeicherten Antworten „aus Memory/Disk-Cache“; Sie sollten dort nicht mit deaktiviertem Cache testen, sonst sehen Sie das Wiederholungsverhalten nicht.

Achten Sie auf Vary: Der Header teilt Caches mit, nach welchen Anfrage-Headern sich die Antwort unterscheidet. Vary: Accept-Encoding ist normal (komprimiert oder unkomprimiert). Vary: Cookie oder Vary: User-Agent machen CDN-Caching sehr ineffizient, weil für jede Kombination eine eigene Kopie entsteht.

Welche typischen Fehler passieren?

FehlerFolgeGegenmaßnahme
Lange max-age für Dateien ohne VersionsnamenBesucher sehen nach Updates altes CSS/JS, bis die Frist abläuftHash/Version im Dateinamen, oder kürzere Frist
Lange Frist für HTMLNeue Inhalte erscheinen verspätet, Links auf alte Assetsno-cache oder kurze Frist
no-cache mit „nicht speichern“ verwechseltSensible Inhalte bleiben gespeichertno-store für wirklich vertrauliche Inhalte
Personalisierte Seiten ohne private in CDNAuslieferung fremder Inhalte an andere Nutzerprivate, no-store; CDN-Regeln prüfen
Kein Cache-Control überhauptHeuristiken entscheiden, unvorhersehbares VerhaltenHeader ausdrücklich setzen
Set-Cookie auf statischen DateienCDNs und Proxys cachen die Antwort nicht oder nur eingeschränktCookies auf statischen Pfaden vermeiden
Doppelte oder widersprüchliche Header (Anwendung, Server, CDN)Unklarer effektiver WertAn einer Stelle setzen; Ergebnis mit curl prüfen
Fehlerseiten werden gecachtKurzer 500er wird lange ausgeliefertFehlerantworten ohne lange Frist; no-store bei 5xx
Mit immutable auf Dateien mit festem NamenEin Fehler kann ein Jahr im Browser steckenNur mit Fingerprinting einsetzen

Ein besonders tückischer Fall: Ein Wartungs- oder Fehlerhinweis, der mit Status 200 und langer Frist ausgeliefert wird, bleibt in Browsern und CDNs liegen, obwohl die Seite längst wieder läuft. Das erklärt manche Meldungen wie „bei mir geht es noch nicht“ nach einer Störung (siehe Ausfallursachen von Websites) und ist ein Grund, Wartungsseiten mit Status 503 und ohne Caching auszuliefern.

Checkliste: Caching prüfen

  1. Haben alle statischen Dateien einen Cache-Control-Header mit sinnvoller Frist?
  2. Haben veränderliche Dateien einen Hash oder eine Version im Namen, bevor Sie immutable setzen?
  3. Ist HTML mit no-cache oder kurzer Frist ausgeliefert und mit ETag oder Last-Modified versehen?
  4. Sind personalisierte Bereiche (Solo, Warenkorb, Checkout) mit private, no-store markiert?
  5. Kommt bei der Revalidierung mit If-None-Match ein 304?
  6. Sind Header nur an einer Stelle gesetzt oder bewusst abgestimmt (Anwendung, Server, CDN)?
  7. Haben Wartungs- und Fehlerseiten keinen langen Cache-Wert?
  8. Nach einem Deployment: CDN-Cache bei Bedarf leeren und prüfen, ob die neuen Dateinamen ankommen.

Grenzen und Einordnung

Caching ist eine Optimierung, kein Reparaturmittel: Eine langsame Anwendung wird durch Header nicht schneller, sondern nur seltener belastet. Und das Verhalten hängt von jedem Glied der Kette ab. Browser unterscheiden sich im Detail, manche CDNs ignorieren Direktiven oder überschreiben sie nach eigenen Regeln, und Cache-Plugins können Ihre Einstellungen ersetzen. Eine Prüfung von außen zeigt, welche Header ankommen, aber nicht, wie jeder einzelne Browser oder jedes CDN damit umgeht. Fehler in der Cache-Steuerung sind zudem selten ein Ausfall im Sinne eines Monitors: Die Seite antwortet mit 200, nur eben mit veraltetem Inhalt. Sie erkennen sie deshalb am ehesten durch gezielte Prüfungen, etwa einen Keyword-Monitor auf einen erwarteten Inhalt, nicht durch reine Verfügbarkeitsprüfung.

Wie setzen Sie das mit UPTIMESHIELD um?

Der Sofort-Report fragt die Cache-Steuerung Ihrer Seite ab und führt sie als Teil der Technik-Bewertung samt Hinweisen in der Maßnahmenliste auf. Das Verfahren zur Messung ist in der Messmethodik beschrieben. Wiederkehrende Kontrollen übernehmen die Website-Checks im Dashboard, die Notenverlauf und Veränderungen („neu“ oder „behoben“) festhalten, etwa wenn nach einem Relaunch plötzlich Cache-Header fehlen (siehe Relaunch und Umzug überwachen). Ob der Inhalt tatsächlich aktuell ist, prüft ein Keyword-Monitor auf einen erwarteten Text. Die Funktionen setzen ein kostenloses Solo-Konto voraus (Registrierung).

Quellen und weiterführende Standards

Externe Links führen zu den Original-Spezifikationen und offiziellen Dokumentationen. Die Einordnung und die Beispielrechnungen stammen aus der Messmethodik von UPTIMESHIELD.

Selbst prüfen: Testen Sie jetzt, ob Ihre Website erreichbar ist und wie schnell sie antwortet – mit dem Uptime Checker.

Häufige Fragen zum Thema

Was ist der Unterschied zwischen no-cache und no-store?
no-cache erlaubt das Speichern, verlangt aber vor jeder Nutzung eine Rückfrage beim Server (Revalidierung). no-store verbietet das Speichern vollständig und ist für sensible Inhalte gedacht.
Welche max-age sollte ich für CSS und JavaScript setzen?
Wenn die Dateinamen einen Hash oder eine Version enthalten, max-age=31536000 (ein Jahr) mit immutable. Haben die Dateien feste Namen, wählen Sie eine kürzere Frist oder Revalidierung, sonst sehen Besucher nach Updates alte Versionen.
Warum sehe ich nach einem Update noch die alte Seite?
Meist liegt die alte Version im Browser-Cache oder in einem CDN, weil die Frist noch nicht abgelaufen ist oder die Dateinamen gleich blieben. Fingerprinting der Dateinamen, kurze Fristen für HTML und gezielte Cache-Leerung beheben das.
Wie prüfe ich, ob mein Caching funktioniert?
Mit curl -sI sehen Sie Cache-Control, ETag und Last-Modified. Senden Sie If-None-Match mit dem ETag mit, sollte der Server 304 antworten. Im Browser zeigt die Netzwerkansicht, ob Dateien aus dem Cache kommen.
Brauche ich den Expires-Header noch?
Nein, wenn Sie Cache-Control mit max-age setzen: Dann wird Expires ignoriert. Er ist nur für sehr alte Clients nötig; Server-Direktiven wie expires in nginx setzen beide Header automatisch.
Dürfen Online-Shop-Seiten gecacht werden?
Öffentliche Seiten wie Kategorien und Produkte meist kurz ja, Warenkorb, Konto und Checkout nicht. Diese Bereiche gehören mit private und no-store markiert, damit keine Inhalte zwischen Nutzern vermischt werden.