Nginx add_header - So konfigurierst du HTTP-Header richtig

Nginx-Konfiguration zeigt `add_header` für benutzerdefinierte Werte.

Geschrieben von

Rolf Fuhrmann

Veröffentlicht am

1. Juni 2026

Inhaltsverzeichnis

Mit nginx add_header steuere ich, welche HTTP-Response-Header Nginx an den Client schickt. Das ist für Sicherheitsheader, Cache-Verhalten und saubere Weiterleitungen relevant, vor allem wenn Backend und Webserver zusammenarbeiten. In der Praxis entscheiden ein paar kleine Details darüber, ob ein Header zuverlässig erscheint oder nur auf einem Teil der Antworten.

Die wichtigsten Punkte zu Response-Headern in Nginx

  • `add_header` setzt Response-Header, nicht Request-Header.
  • Ohne `always` greift die Direktive nur für bestimmte Statuscodes.
  • Ein Header auf einer tieferen Ebene kann vererbte Header ausblenden.
  • Seit NGINX 1.29.3 lässt sich dieses Verhalten mit `add_header_inherit` gezielter steuern.
  • Für Security-Header und statische Dateien braucht es meist unterschiedliche Regeln.
  • Ich teste Header immer mit `curl`, nicht nur im Browser.

Was die Direktive in Nginx wirklich macht

Die Direktive hängt immer an der Antwort, nicht an der Anfrage. Genau deshalb ist sie so nützlich für Security- und Cache-Themen: Ich entscheide damit, welche Header der Browser nach dem Response wirklich sieht. Mehrere `add_header`-Anweisungen sind erlaubt, und der Wert kann Variablen enthalten.

Kontext Wofür ich ihn nutze Praktischer Hinweis
http Globale Vorgaben für alle Sites Sinnvoll für Standards, die wirklich überall gelten sollen.
server Regeln pro Virtual Host Der typische Ort für Domain-spezifische Header.
location Feinsteuerung für Pfade Gut für statische Assets, APIs oder Sonderfälle.
if in location Bedingte Ausnahmen Nur einsetzen, wenn es wirklich nötig ist, sonst wird die Konfiguration schnell unübersichtlich.

Ich setze die Direktive deshalb nicht nach Gefühl ein, sondern als Teil einer klaren Header-Strategie. Das nächste Thema ist dabei entscheidend: Ein Header ist nur dann wirklich nützlich, wenn er auf den Antworten auftaucht, die du absichern willst.

Warum der Header nicht auf jede Antwort geht

Standardmäßig sendet Nginx Header nur bei 200, 201, 204, 206, 301, 302, 303, 304, 307 und 308. Für Sicherheitsheader ist das oft zu eng, weil ein 404 oder 500 genau dann ohne HSTS oder Referrer-Policy zurückkommt, wenn man es am wenigsten will.

Status Standardverhalten Was das in der Praxis bedeutet
2xx Header werden gesetzt Normale erfolgreiche Antworten sind meist unkritisch.
3xx Header werden gesetzt Weiterleitungen bekommen die Direktive ebenfalls mit.
4xx / 5xx Header werden nicht gesetzt Fehlerseiten bleiben ohne zusätzliche Absicherung, wenn du nichts änderst.

`always` ist deshalb keine Zierde, sondern meist die eigentliche Absicherung. Für HSTS, CSP oder ähnliche Policy-Header setze ich es fast immer, weil sich Fehlerseiten, Authentifizierungsfehler und interne Weiterleitungen sonst anders verhalten als der normale 200er-Pfad. Genau an dieser Stelle entstehen die Konfigurationen, die im Alltag „meistens funktionieren“ und in der Fehlersituation plötzlich leer laufen.

Wie Vererbung in server- und location-Blöcken funktioniert

Die klassische Vererbung in Nginx ist streng: Sobald auf einer unteren Ebene mindestens ein `add_header` steht, werden die Header von oben nicht mehr automatisch übernommen. Das überrascht viele, weil ein zusätzlicher Header in `location /api/` nebenbei den globalen HSTS-Header ausblenden kann.

http {
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    server {
        location /api/ {
            add_header Content-Security-Policy "default-src 'self'" always;
        }
    }
}

Mit NGINX 1.29.3 lässt sich das gezielter lösen. Die Direktive `add_header_inherit merge;` kombiniert die Header der höheren Ebene mit den Headern der aktuellen Ebene, statt sie zu ersetzen. Das ist für größere Setups ein echter Gewinn, weil ich globale Sicherheitsheader nicht mehr in jedem einzelnen Block nachbauen muss.

http {
    add_header_inherit merge;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    server {
        location /api/ {
            add_header Content-Security-Policy "default-src 'self'" always;
        }
    }
}

Das `merge`-Verhalten ist der Punkt, an dem sich moderne Konfigurationen deutlich entspannen. Auf älteren Versionen bleibt oft nur, Header in Include-Dateien auszulagern oder sie bewusst in jedem relevanten Block zu wiederholen. Beides ist machbar, aber deutlich fehleranfälliger als die neue Vererbungssteuerung.

Welche Header ich für Sicherheit und Cache setze

Clients connect via NGINX, which can add headers. NGINX then routes requests to Web Server 1 or Web Server 2.

Für produktive Setups trenne ich klar zwischen Sicherheitsheadern für HTML-Seiten und Cache-Regeln für statische Assets. Genau diese Trennung verhindert, dass ich CSS, Bilder oder JavaScript genauso behandle wie ein Login-Formular.

Header Wofür ich ihn nutze Worauf ich achte
Strict-Transport-Security Erzwingt HTTPS im Browser Nur auf HTTPS ausliefern, meist mit always.
Content-Security-Policy Begrenzt erlaubte Quellen für Skripte, Bilder und andere Ressourcen Immer auf die echte Anwendung zuschneiden, nie blind kopieren.
X-Frame-Options Schützt vor Einbettung in fremde Frames Für neue Setups ist `frame-ancestors` in CSP oft die sauberere Lösung, der Header bleibt aber kompatibel.
X-Content-Type-Options Verhindert MIME-Sniffing Praktisch als schlanker Basisschutz.
Referrer-Policy Steuert, wie viel Referrer-Information mitgeht Hilfreich für Datenschutz und weniger Leaking von Pfaden.
Cache-Control Regelt Caching sehr präzise Besonders wichtig bei statischen Assets und dynamischen APIs.
server {
    listen 443 ssl http2;
    server_name example.de;

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Content-Security-Policy "default-src 'self'; object-src 'none'; base-uri 'self'" always;
}

Bei statischen Dateien arbeite ich oft anders, weil dort die Performance zählt und die Inhalte stabiler sind. Für CSS, JS, Fonts oder Bilder reicht häufig schon ein kontrolliertes Cache-Verhalten:

location ~* \.(css|js|mjs|woff2?|png|jpg|jpeg|gif|svg)$ {
    expires 30d;
    add_header Cache-Control "public, max-age=2592000, immutable";
}

Der wichtige Punkt ist dabei nicht der eine „richtige“ Header, sondern die saubere Zuordnung: Sicherheit für HTML, Caching für Assets, keine pauschalen Regeln für alles. Genau daraus ergeben sich die meisten Fehler, die ich im Alltag sehe.

Welche Fehler mir in der Praxis am häufigsten begegnen

Die meisten Probleme sind keine Nginx-Bugs, sondern Konfigurationsdetails. Ich prüfe deshalb immer zuerst das Verhalten auf Fehlerseiten, Weiterleitungen und untergeordneten Locations, nicht nur auf der Startseite.

Symptom Wahrscheinliche Ursache Sauberer Fix
Header fehlt auf 404 oder 500 `always` fehlt Für Security-Header den Parameter ergänzen.
Header verschwindet nur in einem Unterpfad Ein lokaler `add_header`-Block überschreibt die Vererbung Header auslagern, duplizieren oder `add_header_inherit merge;` nutzen.
Doppelte Cache-Control- oder CSP-Werte Upstream und Nginx setzen denselben Header Eine Ebene als Quelle der Wahrheit festlegen.
CSP bricht die Seite Policy ist zu streng oder unvollständig Mit Nonces, Hashes oder gezielten Ausnahmen arbeiten, nicht pauschal lockern.
Im Browser scheint alles korrekt, mit `curl` aber nicht Cache, Service Worker oder Zwischenproxy verfälschen das Ergebnis Direkt gegen den Origin testen und den Cache bewusst ausschalten.
nginx -t
nginx -s reload
curl -I https://example.de/
curl -I https://example.de/not-found
curl -I https://example.de/redirect

Ich verlasse mich bei solchen Prüfungen lieber auf `curl`, weil der Browser oft mehr Filter, Cache und Sonderlogik mitbringt, als man im ersten Moment denkt. Wenn ein Header auch auf einer 404-Antwort sichtbar ist, bin ich deutlich näher an einer belastbaren Konfiguration. Danach stellt sich die Frage, ob `add_header` überhaupt die richtige Stellschraube ist.

Wann ich andere Direktiven bevorzuge

Nicht jeder Header gehört mit `add_header` in Nginx. Wenn ich einen Request an ein Upstream-System schicke, brauche ich `proxy_set_header`; wenn ich einen vom Upstream gelieferten Response-Header entfernen will, nutze ich die passende `*_hide_header`-Direktive. Das ist sauberer, als Request- und Response-Header miteinander zu vermischen.

Aufgabe Passende Direktive Warum ich sie bevorzuge
Header an das Backend senden proxy_set_header Das betrifft den Request, nicht die Antwort.
Header des Backends unterdrücken proxy_hide_header oder das passende Pendant für FastCGI, uWSGI oder SCGI So vermeide ich doppelte oder widersprüchliche Response-Header.
Komplexe, dynamische Header-Logik Anwendung oder njs Wenn die Logik pro Benutzer, Rolle oder Inhalt variiert, ist das meist der klarere Ort.
Globale Header über viele Locations hinweg konsistent halten add_header_inherit merge; oder Include-Datei Das reduziert Copy-Paste und Konfigurationsdrift.

Ich vermeide hier auch unnötig verschachtelte `if`-Konstruktionen, wenn sich die gleiche Entscheidung einfacher im Layout der Konfiguration abbilden lässt. Je weniger Sonderwege du baust, desto besser lässt sich später nachvollziehen, warum ein bestimmter Header auf einer Route existiert oder fehlt.

Was sich in produktiven Setups am besten bewährt

In meinen Augen gewinnt eine Nginx-Konfiguration dann, wenn sie vorhersehbar bleibt. Deshalb setze ich globale Sicherheitsheader möglichst hoch oben, ergänze nur wenige Ausnahmen pro Location und teste immer den kritischen Pfad mit Fehlercodes. Wenn eine Regel kompliziert wird, ist das oft ein Zeichen dafür, dass sie eher in ein Include, ins Backend oder in eine klarere Trennung von statischen und dynamischen Pfaden gehört.

  • Globale Security-Header so weit oben wie möglich definieren.
  • `always` für Header verwenden, die auch auf Fehlerseiten gelten sollen.
  • Bei vielen Unterpfaden `add_header_inherit merge;` einplanen.
  • Statische Assets und HTML getrennt behandeln.
  • Nach jeder Änderung mit `nginx -t` und `curl -I` prüfen.

So bleibt die Konfiguration auch dann beherrschbar, wenn später weitere Standorte, Backends oder Security-Vorgaben dazukommen.

Häufig gestellte Fragen

`add_header` fügt Header zur Nginx-Antwort an den Client hinzu. `proxy_set_header` sendet Header an den Upstream-Server (Backend) als Teil der Anfrage von Nginx. Sie dienen unterschiedlichen Zwecken im Request-Response-Zyklus.

Standardmäßig wendet Nginx `add_header` nur auf Antworten mit bestimmten Statuscodes (z.B. 2xx, 3xx) an. Um Header auch auf Fehlerseiten (4xx, 5xx) zu setzen, musst du das Schlüsselwort `always` zur Direktive hinzufügen, z.B. `add_header Strict-Transport-Security "..." always;`.

Ab NGINX 1.29.3 kannst du `add_header_inherit merge;` verwenden. Diese Direktive kombiniert Header von übergeordneten Kontextebenen mit denen der aktuellen Ebene, anstatt sie zu ersetzen. Auf älteren Versionen musst du Header manuell wiederholen oder Includes nutzen.

Nein. `add_header` ist für Response-Header an den Client gedacht. Für Header, die an das Backend gesendet werden sollen, nutze `proxy_set_header`. Wenn ein Backend bereits einen Header sendet, den du entfernen möchtest, verwende `proxy_hide_header`.

Artikel bewerten

Bewertung: 0.00 Stimmenanzahl: 0

Tags:

nginx add_header nginx add_header konfiguration nginx http header setzen nginx security header nginx cache header add_header always nginx

Beitrag teilen

Rolf Fuhrmann

Rolf Fuhrmann

Mein Name ist Rolf Fuhrmann und ich habe über 12 Jahre Erfahrung im Bereich IT-Infrastruktur, Web-Technologien und Sicherheit. Schon früh entwickelte ich eine Begeisterung für die digitale Welt und die Herausforderungen, die sie mit sich bringt. Besonders fasziniert mich die Schnittstelle zwischen Technologie und Sicherheit, da ich oft beobachte, wie wichtig ein durchdachter Umgang mit Daten und Systemen ist. In meinen Beiträgen möchte ich komplexe Themen verständlich aufbereiten und aktuelle Trends beleuchten. Dabei lege ich großen Wert auf sorgfältige Recherche und den Vergleich verschiedener Informationsquellen, um meinen Lesern präzise und nützliche Inhalte zu bieten. Ich freue mich darauf, mein Wissen und meine Perspektiven mit Ihnen zu teilen und gemeinsam die spannende Welt der IT und Sicherheit zu erkunden.

Kommentar schreiben