Cache-Control auf Hetzner konfigurieren

Sicherheitsrelevantes Caching auf Ihrem Hetzner Cloud Server einrichten — mit differenzierten Nginx location blocks für statische Assets, dynamische Seiten und sensible Bereiche wie Login und Dashboard.

Hetzner · Schritt für Schritt

Cache-Control auf Hetzner Cloud Servern

Cache-Control ist der HTTP-Header, der bestimmt, ob und wie lange Browser und Proxies Inhalte zwischenspeichern. Aus Security-Perspektive ist er entscheidend: Ohne no-store auf sensiblen Seiten können Login-Daten, Dashboard-Inhalte oder API-Responses im Browser-Cache verbleiben — auch nach dem Logout. Im Wolf-Agents Web Security Check fließt Cache-Control mit 8 von 166 Punkten in die Bewertung ein.

Auf einem Hetzner Cloud Server (CX, CPX, CAX oder Dediziert) haben Sie volle Kontrolle über die Webserver-Konfiguration. Das ermöglicht eine differenzierte Caching-Strategie: aggressives Caching für statische Assets, Revalidierung für dynamische Seiten und striktes no-store für sensible Bereiche. Beachten Sie dabei die Besonderheiten des Hetzner Load Balancers und der Hetzner CDN-Integration, die eigene Cache-Header hinzufügen können.

1 Schritt 1 von 3

Caching-Strategie nach Content-Typ definieren

Auf einem Hetzner vServer läuft typischerweise Nginx (Standard bei Hetzner Apps) oder Apache. Die richtige Cache-Strategie unterscheidet drei Kategorien: Statische Assets mit Fingerprinting bekommen maximales Caching, dynamische Seiten erhalten kurze Caches mit Revalidierung und sensible Bereiche wie Login, Dashboard und API dürfen nie gecacht werden.

Nginx — Statische Assets
/etc/nginx/conf.d/cache-control.conf Produktiv
# /etc/nginx/conf.d/cache-control.conf
# Statische Assets: aggressives Caching (1 Jahr)
location ~* \.(css|js|woff2|woff|ttf|eot|svg|png|jpg|jpeg|webp|avif|gif|ico)$ {
    add_header Cache-Control "public, max-age=31536000, immutable" always;
    add_header Vary "Accept-Encoding" always;
}
Nginx — Dynamische Seiten
/etc/nginx/conf.d/cache-control.conf Ergänzung
# Dynamische Seiten: kurzer Cache mit Revalidierung
location / {
    add_header Cache-Control "public, max-age=0, must-revalidate" always;
    add_header Vary "Accept-Encoding, Cookie" always;
}
Nginx — Sensible Bereiche
/etc/nginx/conf.d/cache-control.conf Sicherheitskritisch
# Sensible Bereiche: kein Caching
location /login {
    add_header Cache-Control "no-store, no-cache, must-revalidate" always;
    add_header Pragma "no-cache" always;
}

location /dashboard {
    add_header Cache-Control "no-store, no-cache, must-revalidate, private" always;
    add_header Pragma "no-cache" always;
}

location /api/ {
    add_header Cache-Control "no-store, private" always;
}
In Nginx überschreibt ein innerer location-Block die add_header-Direktiven des äußeren Blocks vollständig. Wenn Sie in einem Location-Block einen einzelnen Header setzen, gehen alle anderen Header des übergeordneten Blocks verloren. Definieren Sie daher alle Header in jedem Block explizit.
2 Schritt 2 von 3

Apache-Konfiguration mit mod_expires und mod_headers

Wenn Ihr Hetzner Server Apache verwendet, benötigen Sie die Module mod_expires (für automatische Expiry-Zeiten nach MIME-Typ) und mod_headers (für explizite Cache-Control-Header auf sensiblen Bereichen). Aktivieren Sie beide Module mit sudo a2enmod expires headers.

/etc/apache2/conf-available/cache-control.conf Produktiv
# /etc/apache2/conf-available/cache-control.conf
<IfModule mod_expires.c>
    ExpiresActive On

    # Statische Assets: 1 Jahr
    ExpiresByType text/css "access plus 1 year"
    ExpiresByType application/javascript "access plus 1 year"
    ExpiresByType image/png "access plus 1 year"
    ExpiresByType image/jpeg "access plus 1 year"
    ExpiresByType image/webp "access plus 1 year"
    ExpiresByType font/woff2 "access plus 1 year"

    # HTML: keine automatische Zwischenspeicherung
    ExpiresByType text/html "access plus 0 seconds"
</IfModule>

<IfModule mod_headers.c>
    # Sensible Bereiche: kein Caching
    <LocationMatch "^/(login|dashboard|api)">
        Header always set Cache-Control "no-store, no-cache, must-revalidate, private"
        Header always set Pragma "no-cache"
    </LocationMatch>

    # Vary-Header für Content Negotiation
    Header always append Vary "Accept-Encoding"
</IfModule>
Apache-Module aktivieren

Aktivieren Sie die Konfiguration mit sudo a2enconf cache-control && sudo systemctl reload apache2. Falls mod_expires fehlt, gibt Apache keinen Fehler aus — die Direktiven werden stillschweigend ignoriert.

3 Schritt 3 von 3

Verifizierung und Monitoring

Prüfen Sie die Header mit curl für verschiedene URL-Typen. Achten Sie besonders darauf, dass sensible Bereiche tatsächlich no-store zurückgeben und statische Assets den immutable-Wert enthalten.

Terminal Verifizierung
# Nginx-Konfiguration testen und laden
sudo nginx -t && sudo systemctl reload nginx

# Apache-Konfiguration testen und laden
sudo apachectl configtest && sudo systemctl reload apache2

# Cache-Control auf statischen Assets prüfen
curl -sI https://ihre-domain.de/assets/style.css | grep -i cache-control
# Erwartet: cache-control: public, max-age=31536000, immutable

# Cache-Control auf Login-Seite prüfen
curl -sI https://ihre-domain.de/login | grep -i cache-control
# Erwartet: cache-control: no-store, no-cache, must-revalidate

# Vary-Header prüfen
curl -sI https://ihre-domain.de | grep -i vary
# Erwartet: vary: Accept-Encoding
Der Wolf-Agents Web Security Check prüft Cache-Control automatisch und zeigt, ob sensible Bereiche korrekt geschützt sind. Nutzen Sie das Monitoring, um Änderungen an den Cache-Headern kontinuierlich zu überwachen.

Häufige Fehler bei Cache-Control auf Hetzner

Hetzner CDN/Load Balancer fügt eigene Cache-Header hinzu

Der Hetzner Load Balancer und externe CDN-Dienste können eigene Cache-Control-Header hinzufügen oder bestehende überschreiben. Das führt zu doppelten Cache-Headern. Prüfen Sie mit curl -sI, ob zwei Cache-Control-Header gesendet werden. Lösung: Setzen Sie Header auf dem Backend und konfigurieren Sie den Load Balancer so, dass er Backend-Header durchreicht statt eigene zu setzen.

Browser cacht sensible Seiten nach Logout

Ohne no-store speichert der Browser die HTML-Seite im Disk-Cache. Ein anderer Nutzer am selben Rechner kann über die Zurück-Taste Dashboard-Inhalte sehen — selbst nach dem Logout. Nur no-store verhindert das vollständig. no-cache allein reicht nicht, da es nur eine Revalidierung erzwingt, die Seite aber trotzdem gecacht bleibt.

Verwechslung: no-cache vs. no-store

no-cache bedeutet: Der Browser darf die Ressource cachen, muss aber vor jeder Verwendung beim Server nachfragen (Revalidierung). no-store bedeutet: Die Ressource darf überhaupt nicht gespeichert werden — weder im Disk- noch im Memory-Cache. Für Login-Seiten, Dashboards und API-Responses ist immer no-store die richtige Wahl.

Fehlender Vary-Header für Content Negotiation

Ohne Vary: Accept-Encoding liefern Proxy-Caches möglicherweise eine gzip-komprimierte Antwort an einen Client, der kein gzip unterstützt (oder umgekehrt). Bei Seiten mit unterschiedlichen Inhalten pro Cookie (z.B. eingeloggt vs. ausgeloggt) ist Vary: Cookie notwendig, damit der Cache die Varianten unterscheidet.

Compliance-Relevanz

Sicherheitsrelevantes Caching ist in mehreren Regelwerken verankert. Ohne korrektes no-store auf sensiblen Seiten riskieren Sie, dass personenbezogene Daten im Browser-Cache verbleiben — ein direkter Verstoß gegen Datenschutzprinzipien.

NIS2 Artikel 21 fordert technische Maßnahmen zur Cybersicherheit — korrektes Caching verhindert, dass sensible Daten unkontrolliert auf Endgeräten verbleiben.
DSGVO Artikel 32 (Sicherheit der Verarbeitung) verlangt angemessene technische Maßnahmen. Das Caching personenbezogener Daten ohne no-store widerspricht dem Grundsatz der Datenminimierung.
PCI DSS PCI DSS 4.0 fordert den Schutz von Zahlungsdaten in Transit und at Rest. Browser-Caches zählen als "at rest" — ohne no-store können Kartendaten lokal gespeichert werden.
BSI APP.3.1 (Webserver-Absicherung) empfiehlt die Konfiguration von Caching-Headern als Teil der Webserver-Härtung.

Wie steht Ihre Domain bei Cache-Control?

Prüfen Sie es jetzt — kostenlos, ohne Registrierung, mit 166 Prüfpunkte.