Zum Inhalt springen
Planen wir gemeinsam die passende Software für Ihre Prozesse. Demo oder Angebot: +90 546 737 48 29

TR EN DE

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

  1. Unbekannte Hostnamen abweisen, Version verbergen

    Nginx gleicht den Host-Header einer eingehenden Anfrage mit den server_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 definierte server-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 dem Server-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.

    Schema: Eine Anfrage, deren Host-Header zu einer konfigurierten Domain passt, geht an den Website-Block; eine Anfrage per IP-Adresse oder mit unbekanntem Namen wird im Standardblock mit 444 geschlossen : Vergrößern
  2. 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 im http-Block definiert: Sie legen den Schlüssel (meist die Client-Adresse, $binary_remote_addr), Namen und Größe des gemeinsamen Speicherbereichs und bei limit_req_zone zusätzlich die Rate fest. Angewendet wird die Grenze in einem server- oder location-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; und limit_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 einem location-Block ein limit_req definiert, gilt das limit_req der übergeordneten Ebene in diesem Block nicht.

    Achtung: Steht Nginx hinter einem CDN oder einem anderen Proxy, ist $binary_remote_addr nicht 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 Direktiven set_real_ip_from und real_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.

    Schema: drei Fälle der Ratenbegrenzung; nur mit rate wird der Überschuss abgewiesen, mit burst wird er eingereiht und verzögert, mit burst und nodelay werden eingereihte Anfragen sofort verarbeitet, was die Warteschlange übersteigt, erhält 429 : Vergrößern
  3. Sicherheitsheader und die Vererbungsfalle bei add_header

    Sicherheitsheader aktivieren die eingebauten Schutzfunktionen des Browsers. In Nginx werden sie mit add_header ergänzt; das abschließende always sorgt 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 kein add_header steht. Sobald Sie in einem location-Block ein einziges add_header schreiben (etwa einen Cache-Header), verschwinden in diesem Block alle Sicherheitsheader der server-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 include in jeden Block einzubinden, der add_header verwendet. Prüfen Sie nach der Änderung mit curl -sI nicht nur die Startseite, sondern auch statische Dateien und Fehlerseiten.

    Vergleich: Steht in einem location-Block ein einzelnes add_header, werden die Sicherheitsheader der server-Ebene nicht vererbt; richtig ist, die gemeinsamen Header per include auch in diesem Block zu definieren : Vergrößern
  4. 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 keine location-Blöcke mit regulären Ausdrücken mehr geprüft werden; Anfragen unterhalb von .well-known fallen 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.

  5. 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 allow und deny werden in der Reihenfolge geprüft, in der sie geschrieben sind; die erste passende Regel gilt, deshalb steht deny 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 Block location /admin/, landet die Anfrage nach /admin/index.php im 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.

    Schema: Die Anfrage nach /admin/index.php wird nicht im gewöhnlichen Präfix-Block, sondern im PHP-Block mit regulärem Ausdruck verarbeitet, die IP-Beschränkung wird umgangen; mit ^~ wird der Präfix-Block gewählt und die Beschränkung greift : Vergrößern
  6. 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:

    DirektiveWas wird begrenzt?StandardBei Überschreitung
    client_max_body_sizeDie maximale Größe des Anfrage-Bodys (zum Beispiel einer hochgeladenen Datei)1m413
    client_body_timeoutDie Zeit zwischen zwei aufeinanderfolgenden Lesevorgängen beim Lesen des Bodys60s408
    client_header_timeoutDie Zeit für das Lesen der gesamten Anfrage-Header60s408
    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_filesize und post_max_size zu 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.

  7. 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.

    Schichtenschema: Standardserver, Ratenbegrenzung, Anfragegrenzen, Zugriffsbeschränkungen, Sicherheitsheader und ganz innen die Anwendung : 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; burst sollte 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_conn als 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 Host erreichen 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 always definiert und in untergeordneten Blöcken mit add_header wiederholt.
  • Dateien mit führendem Punkt und Sicherungsendungen sind gesperrt; .well-known ist 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 -t geprü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

Sprechen wir über die Infrastruktur Ihrer Website

BYK Yazılım entwickelt Unternehmenswebsites. Schreiben Sie uns bei Fragen zu Ihrer Website.

Kontakt aufnehmen Unternehmenswebsite