Nginx-Sicherheitseinstellungen: Ratenbegrenzung, Header, Zugriffsbeschränkungen
Nginx ist die erste Station für jede Anfrage an Ihre Website. Deshalb lassen sich viele Schutzmaßnahmen hier einrichten, ohne den Code der Anwendung anzufassen: Adressen ausbremsen, die zu viele Anfragen senden, Dateien sperren, die nicht offen liegen dürfen, die Verwaltungsseite nur für bestimmte Adressen öffnen und zu große oder zu langsame Anfragen abbrechen.
Diese Einstellungen schließen keine Schwachstellen in der Anwendung; sie sind eine vorgelagerte Schicht, die die Folgen eines Fehlers verringert und den Großteil automatisierter Scans stoppt, bevor er die Anwendung erreicht. Die Anleitung erklärt, wozu jede Einstellung dient und wie sie in der Nginx-Konfiguration geschrieben wird. Die Einrichtung von HTTPS behandelt eine eigene Anleitung: HTTPS in Nginx.
Kurz gefasst
- Anfragen mit unbekanntem Hostnamen werden in einem Standard-Serverblock abgewiesen.
- limit_req und limit_conn begrenzen Anfragen und Verbindungen von einer einzelnen Adresse.
- Steht in einem untergeordneten Block ein add_header, werden die übergeordneten Header nicht vererbt; gemeinsame Header müssen wiederholt werden.
- Versteckte Dateien, Admin-Pfad und Upload-Verzeichnis werden mit eigenen location-Blöcken geschützt.
Achtung
Ergänzen Sie die Einstellungen einzeln und prüfen Sie nach jeder Änderung mit „nginx -t“. Eine falsche IP-Beschränkung oder eine zu strenge Ratenbegrenzung kann auch Sie selbst und echte Besucher aussperren; wählen Sie die Werte passend zu Ihrem Datenverkehr.
Auf dieser Seite
Härtung in sieben Schritten
-
Unbekannte Hostnamen abweisen, Version verbergen
Nginx gleicht den
Host-Header einer eingehenden Anfrage mit denserver_name-Zeilen ab. Passt keine, übergibt es die Anfrage dem Standardserver des jeweiligen Ports; ohne ausdrückliche Angabe ist das der erste in der Konfiguration definierteserver-Block. Die Folge: Automatisierte Scans, die den Server über die IP-Adresse oder unter einem fremden Domainnamen ansprechen, landen bei Ihrer echten Website.Um das zu verhindern, definieren Sie einen Standardblock (Catch-all), der zu keiner Website gehört.
return 444;ist ein Nginx-eigener Code: Er schließt die Verbindung, ohne eine Antwort zu senden.Nginx# Versionsnummer auf Fehlerseiten und im Server-Header nicht anzeigen server_tokens off; # Standardblock: Anfragen, deren Host zu keiner Website passt server { listen 80 default_server; listen [::]:80 default_server; listen 443 ssl default_server; listen [::]:443 ssl default_server; server_name _; # TLS-Handshake mit unbekanntem Namen abweisen ssl_reject_handshake on; # Verbindung schließen, ohne eine Antwort zu senden return 444; }ssl_reject_handshake on;weist HTTPS-Verbindungen mit unbekanntem Namen ab, ohne ein Zertifikat zu präsentieren, und steht in aktuellen Nginx-Versionen zur Verfügung; bei älteren Versionen muss für diesen Block ein selbstsigniertes Zertifikat definiert werden.server_tokens off;entfernt die Versionsnummer aus Fehlerseiten und aus demServer-Header. Für sich genommen ist das kein Schutz; es liefert nur weniger Informationen an Scans, die ihre Ziele nach Version auswählen. Die eigentliche Maßnahme ist, Nginx aktuell zu halten.
: Vergrößern -
Ratenbegrenzung: limit_req und limit_conn
Die Ratenbegrenzung (Rate Limiting) beschränkt, wie viele Anfragen eine einzelne Adresse in einem bestimmten Zeitraum senden kann. Es gibt zwei getrennte Werkzeuge:
limit_req_zone+limit_req: begrenzt die Anfragerate (zum Beispiel 10 Anfragen pro Sekunde).limit_conn_zone+limit_conn: begrenzt die Zahl der gleichzeitig offenen Verbindungen.
Die
…_zone-Direktiven werden einmal imhttp-Block definiert: Sie legen den Schlüssel (meist die Client-Adresse,$binary_remote_addr), Namen und Größe des gemeinsamen Speicherbereichs und beilimit_req_zonezusätzlich die Rate fest. Angewendet wird die Grenze in einemserver- oderlocation-Block.Nginx# Im http-Block: Zonen werden einmal definiert limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s; limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m; limit_conn_zone $binary_remote_addr zone=conn:10m; # Abgewiesene Anfragen erhalten 429 statt 503 limit_req_status 429; limit_conn_status 429; server { listen 443 ssl; server_name beispiel.de; ssl_certificate /etc/letsencrypt/live/beispiel.de/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/beispiel.de/privkey.pem; # Gesamte Website: 10 Anfragen pro Sekunde, Warteschlange für 20 Anfragen limit_req zone=general burst=20 nodelay; # Höchstens 20 gleichzeitige Verbindungen von einer Adresse limit_conn conn 20; location / { proxy_pass http://127.0.0.1:8080; } # Login-Formular: 5 Anfragen pro Minute location = /login { limit_req zone=login burst=5 nodelay; proxy_pass http://127.0.0.1:8080; } }Zwei Parameter bestimmen das Verhalten:
burst: gibt an, wie viele Anfragen oberhalb der Rate in eine Warteschlange gestellt statt sofort abgewiesen werden. Fehlt die Angabe, wird jede Anfrage über der Rate abgewiesen; für die dicht aufeinanderfolgenden Bild- und Skriptanfragen beim Laden einer Seite ist das zu hart.nodelay: Anfragen in der Warteschlange werden sofort verarbeitet statt zurückgehalten; die Plätze in der Warteschlange werden dagegen mit der festgelegten Rate wieder frei. Fehlt die Angabe, werden die wartenden Anfragen so verzögert, dass die Rate eingehalten wird.
Abgewiesene Anfragen erhalten standardmäßig 503. Mit
limit_req_status 429;undlimit_conn_status 429;stellen Sie auf 429 („zu viele Anfragen“) um; so lassen sie sich in den Logs von echten Serverfehlern unterscheiden. Geben Sie sensiblen Adressen wie dem Login-Formular eine eigene, niedrigere Grenze. Wird in einemlocation-Block einlimit_reqdefiniert, gilt daslimit_reqder übergeordneten Ebene in diesem Block nicht.Achtung: Steht Nginx hinter einem CDN oder einem anderen Proxy, ist
$binary_remote_addrnicht die Adresse des Besuchers, sondern die des vorgeschalteten Servers; die Grenze gilt dann für alle Besucher gemeinsam. Definieren Sie in diesem Fall zuerst die echte Client-Adresse mit den Direktivenset_real_ip_fromundreal_ip_header(nur für Proxy-Adressen, denen Sie vertrauen). Eine Ratenbegrenzung allein hält volumenstarke Angriffe nicht auf; zu den Schutzschichten siehe die Anleitung DDoS- und Bot-Angriffe, zu Anmeldeversuchen die Anleitung Login- und Sitzungssicherheit.
: Vergrößern -
Sicherheitsheader und die Vererbungsfalle bei add_header
Sicherheitsheader aktivieren die eingebauten Schutzfunktionen des Browsers. In Nginx werden sie mit
add_headerergänzt; das abschließendealwayssorgt dafür, dass der Header auch bei Fehlerantworten wie 404 und 500 gesendet wird. Was die einzelnen Header bedeuten, erklärt die Anleitung Sicherheitsheader und HTTPS.Es gibt eine wichtige, Nginx-typische Falle:
add_header-Direktiven werden von der übergeordneten Ebene nur dann vererbt, wenn im aktuellen Block überhaupt keinadd_headersteht. Sobald Sie in einemlocation-Block ein einzigesadd_headerschreiben (etwa einen Cache-Header), verschwinden in diesem Block alle Sicherheitsheader derserver-Ebene.Nginx# server-Ebene: für alle Antworten 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 Permissions-Policy "geolocation=(), camera=(), microphone=()" always; location /assets/ { # In diesem Block steht ein add_header: Die vier Header oben werden hier NICHT vererbt add_header Cache-Control "public, max-age=2592000"; # Lösung: die gemeinsamen Header auch in diesem Block definieren # (die Datei enthält die vier add_header-Zeilen von oben) include /etc/nginx/snippets/sicherheitsheader.conf; }Die zuverlässige Lösung besteht darin, die gemeinsamen Header in einer eigenen Datei zu halten und sie per
includein jeden Block einzubinden, deradd_headerverwendet. Prüfen Sie nach der Änderung mitcurl -sInicht nur die Startseite, sondern auch statische Dateien und Fehlerseiten.
: Vergrößern -
Zugriff auf versteckte Dateien sperren
Dateien und Verzeichnisse, deren Name mit einem Punkt beginnt (
.env,.git,.htpasswd), können Passwörter, Schlüssel und Quellcode enthalten; automatisierte Scans sehen dort zuerst nach. Die einzige Ausnahme ist das Verzeichnis.well-known: Es muss für Standardaufgaben wie die Zertifikatsvalidierung erreichbar bleiben.Nginx# Ausnahme: .well-known bleibt erreichbar (Zertifikatsvalidierung usw.) location ^~ /.well-known/ { allow all; } # Jede Datei und jedes Verzeichnis mit führendem Punkt: .env, .git, .htpasswd ... location ~ /\. { deny all; } # Im Webroot vergessene Sicherungs- und Dump-Dateien location ~* \.(?:sql|bak|old|orig|log|ini)$ { deny all; }Das Zeichen
^~bewirkt, dass bei einem Treffer dieses Präfixes keinelocation-Blöcke mit regulären Ausdrücken mehr geprüft werden; Anfragen unterhalb von.well-knownfallen so nicht unter das allgemeine Verbot. Der dritte Block sperrt Sicherungs- und Dump-Dateien, die im Webroot vergessen wurden. Am besten liegen solche Dateien allerdings gar nicht erst im Webroot: Server- und Hosting-Sicherheit. -
Admin-Pfad und Upload-Verzeichnis schützen
Wird die Verwaltungsoberfläche nur von bestimmten Orten aus genutzt, stoppt eine IP-Beschränkung Passwort-Rateversuche, bevor sie das Login-Formular erreichen. Die Regeln
allowunddenywerden in der Reihenfolge geprüft, in der sie geschrieben sind; die erste passende Regel gilt, deshalb stehtdeny all;am Ende.Nginx# ^~ : Passt dieses Präfix, werden die äußeren Blöcke mit regulären Ausdrücken nicht geprüft location ^~ /admin/ { allow 203.0.113.10; # Büro allow 198.51.100.0/24; # VPN deny all; # Die Beschränkung gilt auch für den PHP-Handler innerhalb des Blocks location ~ \.php$ { include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_pass unix:/run/php/php-fpm.sock; # Pfad hängt von der Distribution ab } }Hier passiert häufig ein Fehler. PHP-Websites haben in der Regel einen Block mit regulärem Ausdruck in der Form
location ~ \.php$. Schreiben Sie die Beschränkung in einen gewöhnlichen Blocklocation /admin/, landet die Anfrage nach/admin/index.phpim Block mit dem regulären Ausdruck, und die Beschränkung wird nicht angewendet. Mit^~und dem PHP-Handler innerhalb des Blocks, wie im Beispiel, lässt sich das vermeiden. Der Pfad des PHP-FPM-Sockets hängt von der Distribution ab.Für das Upload-Verzeichnis gilt dieselbe Logik in umgekehrter Richtung: In einem Verzeichnis, in das Besucher Dateien hochladen können, darf kein Skript ausgeführt werden. Der folgende Block liefert die Dateien des Verzeichnisses ausschließlich als statische Dateien aus und beantwortet Anfragen mit Skript-Endungen mit 403.
Nginx# Upload-Verzeichnis: nur statische Dateien location ^~ /upload/ { # Anfragen mit Skript-Endungen werden weder ausgeführt noch ausgeliefert location ~* \.(?:php|phtml|phar|pl|py|cgi|sh)$ { return 403; } }Das ist die zweite Schicht, die verhindert, dass eine hochgeladene Datei auf dem Server ausgeführt wird; die erste Schicht ist die Prüfung beim Hochladen: Sicherheit beim Datei-Upload.
: Vergrößern -
Große und langsame Anfragen begrenzen
Anfragen mit sehr großem Body verbrauchen Speicherplatz und Arbeitsspeicher; absichtlich sehr langsam gesendete Anfragen belegen Verbindungen über lange Zeit. Drei Direktiven begrenzen beides:
Direktive Was wird begrenzt? Standard Bei Überschreitung client_max_body_sizeDie maximale Größe des Anfrage-Bodys (zum Beispiel einer hochgeladenen Datei) 1m 413 client_body_timeoutDie Zeit zwischen zwei aufeinanderfolgenden Lesevorgängen beim Lesen des Bodys 60s 408 client_header_timeoutDie Zeit für das Lesen der gesamten Anfrage-Header 60s 408 Nginx# Allgemeine Grenzen client_max_body_size 2m; client_body_timeout 15s; client_header_timeout 15s; # Höhere Body-Grenze nur für die Adresse, über die Dateien hochgeladen werden location /datei-upload { client_max_body_size 20m; proxy_pass http://127.0.0.1:8080; }Halten Sie die allgemeine Grenze niedrig und geben Sie der Adresse, über die Dateien hochgeladen werden, einen eigenen, höheren Wert. Wenn Sie PHP einsetzen, müssen auch die Einstellungen
upload_max_filesizeundpost_max_sizezu diesem Wert passen. Zu kurze Zeitüberschreitungen (Timeouts) treffen auch echte Nutzer mit langsamer Mobilfunkverbindung; senken Sie die Werte schrittweise und beobachten Sie die 408-Antworten in den Logs. -
Testen, neu laden und von außen überprüfen
Prüfen Sie nach jeder Änderung die Syntax und laden Sie Nginx neu. Überzeugen Sie sich anschließend mit Anfragen von außen an Ihre eigene Website, dass die Einstellungen wirklich greifen: Adressen versteckter Dateien sollten 403 oder 404 liefern, die Header sollten auch bei statischen Dateien erscheinen, und eine Anfrage an die IP-Adresse des Servers sollte ohne Antwort geschlossen werden.
Bash# Syntax prüfen, dann neu laden sudo nginx -t sudo systemctl reload nginx # Header: Startseite und eine statische Datei curl -sI https://beispiel.de/ curl -sI https://beispiel.de/assets/site.css # Sind versteckte Dateien gesperrt? (403 oder 404 erwartet) curl -s -o /dev/null -w "%{http_code}\n" https://beispiel.de/.env curl -s -o /dev/null -w "%{http_code}\n" https://beispiel.de/.git/config # Anfrage an die IP-Adresse des Servers: sollte ohne Antwort geschlossen werden curl -sI http://203.0.113.20/Halten Sie beim Testen einer IP-Beschränkung eine zweite Sitzung offen; sperrt Sie eine falsche Regel aus der Verwaltungsoberfläche aus, können Sie die Konfiguration aus dieser Sitzung zurücknehmen.
: Vergrößern
Was lösen diese Einstellungen nicht?
- Schwachstellen der Anwendung: SQL-Injection, XSS oder Fehler in der Berechtigungsprüfung werden im Code behoben; eine Nginx-Einstellung ersetzt das nicht.
- Volumenstarke Angriffe: Datenverkehr, der die Bandbreite des Servers füllt, muss abgefangen werden, bevor er den Server erreicht (beim Hosting-Anbieter oder auf CDN-Ebene).
- Verteilte, langsame Versuche: Wenige Anfragen von jeweils vielen verschiedenen Adressen erreichen eine Grenze pro Adresse nicht; die Login-Sicherheit muss auch in der Anwendung umgesetzt sein.
- Übernommene Konten: IP-Beschränkung und Ratenbegrenzung halten niemanden auf, der mit gültigem Passwort von einer erlaubten Adresse kommt; dafür ist die Zwei-Faktor-Authentifizierung nötig.
Wie wählt man die Werte?
Die Zahlen in den Beispielen sind ein Ausgangspunkt, keine Empfehlung. Der richtige Wert hängt vom Datenverkehr Ihrer Website ab:
- Sehen Sie nach, wie viele Anfragen der Browser beim Laden einer Seite sendet;
burstsollte diese Zahl abdecken. - Viele Nutzer aus demselben Firmennetz können unter einer einzigen IP-Adresse erscheinen; lockern Sie die Grenze entsprechend oder behandeln Sie bekannte Adressen gesondert.
- Beobachten Sie nach dem Aktivieren die abgewiesenen Anfragen im Fehlerlog und die 429-Antworten im Zugriffslog; bleiben echte Nutzer hängen, erhöhen Sie den Wert.
- Bei HTTP/2 und HTTP/3 zählt jede gleichzeitige Anfrage für
limit_connals eigene Verbindung; wählen Sie den Wert nicht zu niedrig. - Überlegen Sie, ob Suchmaschinen-Bots und Ihre eigenen Überwachungswerkzeuge von der Grenze ausgenommen werden müssen.
Checkliste
- Für die Ports 80 und 443 ist ein Standardblock definiert; Anfragen mit unbekanntem
Hosterreichen die Website nicht. server_tokens off;ist gesetzt, und Nginx ist aktuell.- Es gibt eine allgemeine Ratenbegrenzung und eine eigene für die Login-Adresse; abgewiesene Anfragen erhalten 429.
- Hinter einem Proxy ist die echte Client-Adresse korrekt definiert.
- Sicherheitsheader sind mit
alwaysdefiniert und in untergeordneten Blöcken mitadd_headerwiederholt. - Dateien mit führendem Punkt und Sicherungsendungen sind gesperrt;
.well-knownist erreichbar. - Der Admin-Pfad ist per IP beschränkt, und die Beschränkung gilt auch für
.php-Anfragen. - Im Upload-Verzeichnis wird kein Skript ausgeführt.
- Grenzen für Body-Größe und Zeitüberschreitung sind definiert; die Upload-Adresse hat einen eigenen Wert.
- Jede Änderung wurde mit
nginx -tgeprüft und von außen überprüft.
Häufige Fragen
Wirkt sich die Ratenbegrenzung auf Suchmaschinen-Bots aus?
Eine sehr niedrige Grenze bremst auch Bots, und eine 429-Antwort verzögert das Crawling. Legen Sie die Grenze anhand Ihres tatsächlichen Datenverkehrs fest und beobachten Sie in den Logs, welche Anfragen abgewiesen werden.
Entfernt server_tokens off den Server-Header vollständig?
Nein. Nur die Versionsnummer entfällt; im Header steht weiterhin „nginx“. Die Einstellung verringert den Informationsabfluss, ersetzt aber keine Updates.
Kann ich statt 444 auch 403 oder 404 zurückgeben?
Ja. Da 444 die Verbindung ohne Antwort schließt, erhalten automatisierte Scans damit die wenigsten Informationen. Erwartet ein Überwachungswerkzeug oder ein Load Balancer von dieser Adresse eine Antwort, verwenden Sie einen Standardcode.
Meine Header sind auf der Startseite vorhanden, bei Bildern aber nicht. Warum?
Sehr wahrscheinlich steht im location-Block für statische Dateien ein eigenes add_header. Nginx vererbt die Header der übergeordneten Ebene dann nicht in diesen Block; definieren Sie die gemeinsamen Header auch dort.
Kann ich diese Einstellungen im Shared Hosting vornehmen?
In der Regel nicht; die Nginx-Konfiguration liegt in der Hand des Serveradministrators. Sie können Ihren Hosting-Anbieter um Unterstützung bitten oder ähnliche Schutzfunktionen über das Kundenpanel und ein CDN aktivieren.
BYK Yazılım Support-Team
Diese Anleitung wird vom Support-Team von BYK Yazılım erstellt und regelmäßig überprüft. Letzte Aktualisierung: 04.10.2026.
Verwandte Anleitungen
- DDoS- und Bot-AngriffeAnzeichen, CDN und WAF, Ratenbegrenzung, Caching und die Zusammenarbeit mit dem Hosting-Anbieter.
- Login- und SitzungssicherheitPasswort-Hashing, Begrenzung der Anmeldeversuche, Session-Fixation, Cookie-Flags und Berechtigungsprüfung bei jeder Anfrage.
- HTTPS in Nginx: SSL-Zertifikat einrichtenZertifikat beziehen, auf HTTPS weiterleiten, HSTS, SSL-Terminierung und automatische Erneuerung in Nginx.
- Sicherheitsheader und HTTPSHSTS, CSP, X-Content-Type-Options, Referrer-Policy und Permissions-Policy; mit .htaccess-Beispiel.
Sprechen wir über die Infrastruktur Ihrer Website
BYK Yazılım entwickelt Unternehmenswebsites. Schreiben Sie uns bei Fragen zu Ihrer Website.
Kontakt aufnehmen Unternehmenswebsite