Vor der Änderung die zuständige Schicht bestimmen
Erfassen Sie die benötigten Origins, Methoden und Requestheader. Klären Sie, ob der Browser credentials: "include" verwendet. Die fachlichen Auswahlregeln stehen in CORS für APIs.
Untersuchen Sie danach die ausgelieferte Antwort und die Antwort des eigenen Upstreams getrennt. Setzt die Anwendung bereits eine vollständige CORS-Regel, kann die richtige nginx-Konfiguration darin bestehen, diese unverändert durchzureichen. Zentrale Header am Proxy sind nur sinnvoll, wenn sie zum Routen- und Clientmodell passen. Browserfreigaben ersetzen keine Autorisierung im Upstream.
Halten Sie die nginx-Version und alle wirksamen Includes fest. add_header ... always gilt auch bei Antwortstatus, die ohne always nicht erfasst werden. Die klassische Vererbung übernimmt add_header-Direktiven einer übergeordneten Ebene nur, wenn auf der aktuellen Ebene keine eigenen definiert sind. Neuere Konfigurationen können diese Regel mit add_header_inherit verändern; die Direktive ist laut Dokumentation seit 1.29.3 vorhanden. Siehe nginx: Headers-Modul.
Eine abgeschlossene lokale Proxy-Demo
Die Konfiguration nutzt ausschließlich Loopback-Adressen. Ein synthetischer Upstream läuft auf Port 43103, der Proxy auf 43102. Als erlaubte Frontend-Origin dient http://127.0.0.1:43101. Es werden keine Anmeldung, echten Cookies, Kundendaten oder externe Ziele verwendet. Die HTTP-Adressen gelten nur für diese lokale Demonstration; sie sind keine Transportvorlage für eine veröffentlichte API.
Speichern Sie den folgenden Inhalt als nginx.conf in einem eigenen leeren Arbeitsverzeichnis. Die Regel verwendet keine fremden Konfigurations-Includes:
worker_processes 1;
pid logs/nginx.pid;
error_log logs/error.log warn;
events {
worker_connections 64;
}
http {
access_log off;
map $http_origin $cors_origin {
default "";
"http://127.0.0.1:43101" "http://127.0.0.1:43101";
}
map $cors_origin $cors_credentials {
default "";
"http://127.0.0.1:43101" "true";
}
server {
listen 127.0.0.1:43103;
server_name localhost;
default_type application/json;
location = /demo/data {
return 200 '{"message":"synthetic data"}';
}
location = /demo/error {
return 503 '{"message":"synthetic unavailable"}';
}
location / {
return 404;
}
}
server {
listen 127.0.0.1:43102;
server_name localhost;
location /demo/ {
proxy_hide_header Access-Control-Allow-Origin;
proxy_hide_header Access-Control-Allow-Credentials;
proxy_hide_header Access-Control-Allow-Methods;
proxy_hide_header Access-Control-Allow-Headers;
proxy_hide_header Access-Control-Expose-Headers;
proxy_hide_header Access-Control-Max-Age;
add_header Access-Control-Allow-Origin $cors_origin always;
add_header Access-Control-Allow-Credentials $cors_credentials always;
add_header Access-Control-Allow-Methods "GET" always;
add_header Access-Control-Allow-Headers "X-Demo" always;
add_header Vary "Origin" always;
if ($request_method = OPTIONS) {
return 204;
}
proxy_pass http://127.0.0.1:43103;
}
location / {
return 404;
}
}
}
Das Map-Modul ordnet erlaubte Werte einer definierten Antwort zu. Eine unbekannte Origin erhält hier einen leeren Wert. Der nginx-Headerfilter fügt einen solchen leeren add_header-Wert nicht hinzu; der offizielle Headerfilterquellcode zeigt die entsprechende Prüfung in ngx_http_add_header.
Das Credentials-Signal demonstriert ausschließlich den CORS-Modus. Es meldet keinen Benutzer an. Ebenso sagt Access-Control-Allow-Methods: GET dem Browser, was der Preflight erlaubt; es sperrt andere Methoden im Upstream nicht. Die Demo verändert unabhängig von der Methode keine Daten. Eine echte Anwendung muss ihren Methoden- und Rechtevertrag selbst durchsetzen.
Doppelte Header und Vererbung bewusst behandeln
proxy_hide_header unterdrückt die bezeichneten Antwortheader des Upstreams. Im Beispiel übernimmt nginx die CORS-Regel vollständig und entfernt deshalb die betreffenden Upstreamwerte. Das ist eine bewusste Eigentumsentscheidung; übernehmen Sie diesen Block nicht, wenn eigentlich die Anwendung unterschiedliche Routenregeln ausgeben soll. Die Funktion dokumentiert das nginx-Proxy-Modul.
Der Vary-Header des Upstreams wird nicht versteckt. Weitere dort benannte Varianten, etwa nach Inhalt oder Kompression, müssen erhalten bleiben. Für dynamische Originfreigabe kommt hier Origin hinzu. Die Demo richtet keinen Antwortcache ein; personalisierte Inhalte benötigen in einer realen Umgebung zusätzlich passende Cache-Control-Regeln.
Die CORS-Header stehen gemeinsam auf derselben Locationebene, und der OPTIONS-Zweig fügt keine abweichenden add_header-Direktiven hinzu. Das vermeidet eine typische unbeabsichtigte Vererbungsänderung. In einer bestehenden Konfiguration kann jedoch bereits das Hinzufügen eigener Locationheader übergeordnete Header verdrängen. Prüfen Sie deshalb auch die sonst benötigten Header dieser Route. Ein isolierter Ausschnitt erklärt nicht sämtliche Regeln des produktiven Servers.
Syntax, Header und Browserwirkung getrennt nachweisen
Voraussetzung für die folgenden Befehle ist eine lokal installierte nginx-Version mit den gezeigten Standardmodulen und freie Demoports. Syntax, Prozessstart und Beenden wurden mit nginx 1.30.5 geprüft. Im eigenen Demoverzeichnis legt der relative Präfix auch PID und Logs ab:
mkdir -p logs
nginx -t -p "$PWD/" -c nginx.conf
nginx -p "$PWD/" -c nginx.conf
Starten Sie nur, wenn die Konfigurationsprüfung erfolgreich war. Ein lokaler Preflight lässt sich anschließend so beobachten:
curl -i -X OPTIONS http://127.0.0.1:43102/demo/data \
-H 'Origin: http://127.0.0.1:43101' \
-H 'Access-Control-Request-Method: GET' \
-H 'Access-Control-Request-Headers: X-Demo'
Erwartet werden 204, genau eine passende Originfreigabe, true, GET und X-Demo. Wiederholen Sie die reine Headerprobe mit einer eigenen nicht erlaubten Test-Origin: Es soll keine passende Originfreigabe erscheinen. Das ist noch kein Browsertest, denn curl erzwingt CORS nicht.
Die vollständige Demo wurde am 27. September 2026 auf macOS 26.0.1 in Chromium 147.0.7727.15, Firefox 148.0.2 und Playwright-WebKit 26.4 seriell geprüft. Die erlaubte Origin konnte Status 200 und 503 samt JSON lesen; die Schaltflächen der nicht erlaubten Origin scheiterten bereits am Preflight, ohne nachfolgenden GET. Eine zusätzliche einfache GET-Anfrage ohne X-Demo wurde dagegen gesendet, ihre Antwort blieb für JavaScript gesperrt. Ein lokaler HTTP-Client ohne Origin konnte die Daten lesen. Eine getrennte Upstreamgegenprobe bestätigte genau eine CORS-Freigabe und den Erhalt von Vary: Accept-Encoding neben Origin, auch bei 503. Ein übergeordneter eigener Header wurde durch die Locationheader wie beschrieben verdrängt. WebKit bezeichnet hier die Playwright-Engine, keinen Test mit nativem Safari oder einem iPhone.
Prüfen Sie außerdem GET auf /demo/data und /demo/error. Für die erlaubte Origin sollen die nötigen Header auch bei 503 vorhanden sein. Der Browser muss aus dem erlaubten Frontendkontext beide Antworten lesen können; der Fehler bleibt dabei ein Fehlerstatus. Aus einem anderen lokalen Origin darf JavaScript die Antworten nicht lesen. Für den lokalen Browsernachweis verwenden Sie den vollständigen Browserclient aus dem Express-Beispiel. Dessen dort genannte Node-/Paketvoraussetzungen gelten weiterhin. Falls der vollständige Express-Demoprozess schon läuft, beenden Sie ihn zuerst mit Ctrl+C; starten Sie dann im Verzeichnis mit demo.mjs den Modus node demo.mjs --ui-only. Er öffnet nur die Browseroberflächen auf 43101 und 43104, lässt aber API-Port 43102 für die separat gestartete nginx-Demo frei. Öffnen Sie die beiden UI-Adressen und verwenden Sie die Schaltflächen für Daten und Fehler. Das optionale Anzeigefeld result darf hier null sein, weil die nginx-Demo keinen X-Demo-Result sendet.
Die eigene Konfiguration kontrolliert einführen
Übernehmen Sie aus der Demo die erforderlichen Prinzipien, nicht deren lokalen Ports oder synthetischen Upstream. Sichern Sie vor einer realen Änderung die wirksame Konfiguration, prüfen Sie den Kandidaten und testen Sie erlaubte Origins, abgelehnte Origins, Voranfragen und Fehlerpfade in einer geeigneten eigenen Umgebung. Beachten Sie vorgelagerte Gateways und interne Fehlerumleitungen.
Für die Demo beendet folgender Befehl nur die nginx-Instanz mit dem angegebenen Präfix und deren PID-Datei:
nginx -p "$PWD/" -c nginx.conf -s quit
Bei einer echten Konfigurationsrücknahme laden Sie den zuvor geprüften sicheren Stand über Ihren bestehenden Betriebsweg und wiederholen den betroffenen Nachweis. Eine zu weite Freigabe wird gezielt geschlossen. Der API Security Check kann öffentliche Header beobachten, validiert aber weder Ihre nginx-Includes noch echte Credentials- oder Browserabläufe. Quellenstand: 27. September 2026.
Quellen und Stand
Quellenstand: 27. September 2026. Die Links stehen zusätzlich bei den jeweils begründeten Aussagen.