Nginx Rate Limiting und DDoS-Schutz

9 Min. Lesezeit·Matthieu·fail2banddos-protectionrate-limitingsecuritynginx|

Konfigurieren Sie Nginx Rate Limiting mit limit_req, limit_conn und fail2ban, um Ihren Server vor Brute-Force-Angriffen und Application-Layer-DDoS zu schützen, ohne auf Drittanbieter-Dienste angewiesen zu sein.

Rate Limiting ist Ihre erste Verteidigungslinie gegen Brute-Force-Angriffe, API-Missbrauch und Application-Layer-DDoS. Dieses Tutorial baut drei Schutzschichten auf, die ausschließlich Nginx und fail2ban verwenden. Keine DDoS-Dienste von Drittanbietern, kein Traffic, der Ihren Server verlässt.

Sie werden Request-Rate-Limiting (limit_req), Verbindungsdrosselung (limit_conn) und automatisches IP-Banning (fail2ban) auf Debian 12 oder Ubuntu 24.04 konfigurieren.

Voraussetzungen:

  • Nginx installiert und aktiv
  • Grundkenntnisse der Nginx-Konfigurationsstruktur
  • Root- oder Sudo-Zugang

Wie funktioniert Nginx Rate Limiting?

Nginx Rate Limiting nutzt den Leaky-Bucket-Algorithmus über die Direktiven limit_req_zone und limit_req. Eingehende Requests füllen einen Eimer mit beliebiger Geschwindigkeit. Der Eimer leert sich mit einer festen Rate, die Sie definieren. Wenn der Eimer überläuft, lehnt Nginx die überschüssigen Requests ab. Das glättet Traffic-Spitzen bei gleichbleibender Verarbeitungsrate.

Die Implementierung umfasst zwei Direktiven. limit_req_zone definiert die Shared-Memory-Zone, die den Client-Status über alle Worker-Prozesse hinweg verfolgt. limit_req wendet das Limit auf bestimmte Locations an.

# Im http-Block: Zone definieren
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

# In einem server- oder location-Block: Limit anwenden
limit_req zone=api;

Der Schlüssel $binary_remote_addr speichert jede Client-IP in einem kompakten Binärformat (4 Bytes für IPv4, 16 Bytes für IPv6). Eine 10-MB-Zone fasst ungefähr 160.000 IPv4-Adressen oder 80.000 IPv6-Adressen. Für die meisten Server reicht 10m aus.

Der Parameter rate akzeptiert Requests pro Sekunde (r/s) oder pro Minute (r/m). Nginx verfolgt dies intern in Millisekunden. Eine Rate von 10r/s bedeutet ein erlaubter Request alle 100 ms.

Wie konfiguriere ich limit_req_zone und limit_req?

Erstellen Sie eine separate Konfigurationsdatei für Rate Limiting:

sudo nano /etc/nginx/conf.d/rate-limiting.conf
# Shared-Memory-Zonen - auf http-Ebene definiert
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
limit_req_zone $binary_remote_addr zone=api:10m rate=30r/s;

# 429 statt des Standard-503 zurückgeben
limit_req_status 429;

# Rate-Limit-Ereignisse auf warn-Level protokollieren (Verzögerungen auf notice)
limit_req_log_level warn;

Wenden Sie die Zonen dann in Ihrem Server-Block an:

sudo nano /etc/nginx/sites-available/example.com
server {
    listen 80;
    server_name example.com;

    # Allgemeines Rate Limit für alle Requests
    limit_req zone=general burst=20 nodelay;

    location /login {
        # Striktes Limit für den Login-Endpoint
        limit_req zone=login burst=3 nodelay;
        proxy_pass http://127.0.0.1:3000;
    }

    location /api/ {
        # Höheres Limit für API-Konsumenten
        limit_req zone=api burst=50 delay=30;
        proxy_pass http://127.0.0.1:3000;
    }

    location / {
        proxy_pass http://127.0.0.1:3000;
    }
}

Testen Sie die Konfiguration und laden Sie neu:

sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
sudo systemctl reload nginx

Wenn eine limit_req-Direktive in einem location-Block definiert ist, überschreibt sie jedes vom server-Level vererbte limit_req. Die Zone general gilt für /, aber nicht für /login oder /api/, da diese Locations eigene limit_req-Direktiven haben. Wenn beide Zonen gelten sollen, fügen Sie mehrere limit_req-Zeilen im selben Block hinzu.

Was bewirken burst, nodelay und delay?

Der Parameter burst steuert, wie viele überschüssige Requests Nginx in die Warteschlange stellt statt sofort abzulehnen. Ohne burst erhält jeder Request über der Rate einen 429. Mit burst hält Nginx überschüssige Requests in einer Warteschlange und gibt sie mit der Basisrate frei.

Parameter Sofortige Requests Warteschlange Abgelehnt Anwendungsfall
burst=0 (Standard) 1 pro Intervall Keine Alles über der Rate Strikte API-Limits
burst=5 1 pro Intervall Bis zu 5, freigegeben mit Basisrate Über burst+1 Formular-Übermittlungen
burst=5 nodelay Bis zu 6 auf einmal Keine in Warteschlange, aber Burst-Slots füllen sich mit Basisrate auf Über burst+1 bis Slots aufgefüllt Login-Seiten, allgemeiner Traffic
burst=20 delay=10 Bis zu 11 auf einmal Requests 12-21 gedrosselt auf Basisrate Über burst+1 APIs mit gelegentlichen Spitzen

Mit burst=5 (ohne nodelay) werden bei 6 gleichzeitigen Requests Request 1 sofort verarbeitet. Requests 2-6 stehen in der Warteschlange und werden einzeln pro Intervall freigegeben (alle 100 ms bei 10r/s). Der letzte Request wartet 500 ms. Das fügt Latenz hinzu, verwirft aber keine legitimen Bursts.

Mit burst=5 nodelay werden alle 6 Requests sofort verarbeitet. Die 5 Burst-Slots brauchen aber 500 ms zum Auffüllen. Wenn 200 ms später 6 weitere Requests eintreffen, haben sich nur 3 Slots aufgefüllt, sodass 3 überschüssige Requests abgelehnt werden.

Mit burst=20 delay=10 werden die ersten 11 Requests (1 Basis + 10 Delay-Schwelle) ohne Wartezeit verarbeitet. Requests 12-21 werden auf die Basisrate gedrosselt. Alles über 21 wird abgelehnt. Dieser Hybrid-Modus eignet sich gut für APIs, die periodische Bursts von legitimen Batch-Clients erhalten.

Wie limitiere ich verschiedene Endpoints separat?

Definieren Sie separate Zonen mit unterschiedlichen Schlüsseln für unabhängige Limits. Das obige Beispiel verwendet bereits drei Zonen. Sie können auch per URI-Pfad limitieren, indem Sie $uri als Schlüssel verwenden:

# Per-URI Rate Limiting: begrenzt die Gesamtanfragen an jede eindeutige URI
limit_req_zone $uri zone=per_uri:10m rate=50r/s;

Das ist nützlich, wenn bestimmte Endpoints (wie eine Suchseite oder eine Exportfunktion) globales Throttling benötigen, unabhängig davon, welcher Client sie aufruft.

Für API-Key-basiertes Rate Limiting verwenden Sie map, um den Schlüssel aus einem Header zu extrahieren:

map $http_x_api_key $api_key_limit {
    default          $binary_remote_addr;
    "~^.+$"          $http_x_api_key;
}

limit_req_zone $api_key_limit zone=api_keyed:10m rate=100r/s;

Wenn der Client einen X-API-Key-Header sendet, basiert das Rate Limit auf diesem Schlüssel. Andernfalls fällt es auf IP-basierte Limitierung zurück.

Wie drossle ich Verbindungen mit limit_conn?

Während limit_req die Request-Rate steuert, begrenzt limit_conn die Anzahl gleichzeitiger Verbindungen pro Client. Das wirkt gut gegen Slowloris-Angriffe und Download-Missbrauch.

# Im http-Block
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_conn_status 429;
limit_conn_log_level warn;
# In einem server- oder location-Block
server {
    # Max 20 gleichzeitige Verbindungen pro IP
    limit_conn addr 20;

    location /downloads/ {
        # Max 2 gleichzeitige Downloads pro IP
        limit_conn addr 2;
        limit_rate 1m;  # Bandbreite auf 1 MB/s pro Verbindung drosseln
    }
}

Hinweis für HTTP/2 und HTTP/3: Jeder gleichzeitige Request zählt als separate Verbindung. Ein Browser, der eine Seite mit 30 Assets über eine einzelne HTTP/2-Verbindung lädt, zählt als 30 Verbindungen für limit_conn. Setzen Sie das Limit höher als bei HTTP/1.1.

limit_conn und limit_req ergänzen sich. Verwenden Sie beide. limit_req stoppt Schnellfeuer-Requests. limit_conn stoppt Verbindungsfluten.

Wie gebe ich eine benutzerdefinierte 429-Fehlerseite zurück?

Standardmäßig erhalten rate-limitierte Requests eine generische Fehlerseite. Eine benutzerdefinierte 429-Seite kann einen Retry-After-Header und eine verständliche Nachricht enthalten.

Erstellen Sie die Fehlerseite:

sudo mkdir -p /var/www/error
sudo nano /var/www/error/429.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>429 - Too Many Requests</title>
    <style>
        body { font-family: system-ui, sans-serif; text-align: center; padding: 5rem 1rem; }
        h1 { font-size: 2rem; }
        p { color: #555; }
    </style>
</head>
<body>
    <h1>429 - Too Many Requests</h1>
    <p>You have exceeded the request limit. Wait a moment and try again.</p>
</body>
</html>
sudo chmod 644 /var/www/error/429.html

Fügen Sie die Fehlerseite und den Retry-After-Header in Ihren Server-Block ein:

server {
    #... Rate-Limiting-Direktiven...

    error_page 429 /429.html;
    location = /429.html {
        root /var/www/error;
        internal;
        add_header Retry-After 5 always;
    }
}

Die Direktive internal verhindert direkten Zugriff auf die Fehlerseite. Das Schlüsselwort always bei add_header stellt sicher, dass der Header auch bei Fehlerantworten gesendet wird. Der Retry-After-Wert (in Sekunden) teilt wohlerzogenen Clients mit, wann sie es erneut versuchen können.

Wie teste ich Rate Limits sicher mit dry_run?

Aktivieren Sie limit_req_dry_run on, um Rate Limiting zu simulieren, ohne Requests abzulehnen. Nginx protokolliert, was es getan hätte, aber alle Requests gehen durch. Diese Option ist seit Nginx 1.17.1 verfügbar.

server {
    limit_req zone=general burst=20 nodelay;
    limit_req_dry_run on;  # Nur protokollieren, nicht durchsetzen

    # Rate-Limit-Status zu Access-Logs hinzufügen
    #...
}

Fügen Sie $limit_req_status zu Ihrem Log-Format hinzu, um Dry-Run-Ereignisse in Access-Logs zu verfolgen:

# Im http-Block
log_format ratelimit '$remote_addr - $remote_user [$time_local] '
                     '"$request" $status $body_bytes_sent '
                     '"$http_referer" "$http_user_agent" '
                     'rate_limit=$limit_req_status';

# Im server-Block
access_log /var/log/nginx/access.log ratelimit;

Der dry_run-Ablauf:

  1. Fügen Sie limit_req_dry_run on; zu Ihrer Konfiguration hinzu
  2. Laden Sie Nginx neu
  3. Erzeugen Sie Test-Traffic (siehe Testabschnitt unten)
  4. Prüfen Sie das Error-Log auf Dry-Run-Einträge:
sudo grep "dry run" /var/log/nginx/error.log
2026/03/19 14:22:31 [warn] 1234#1234: *567 limiting requests, dry run, excess: 1.532 by zone "general", client: 203.0.113.50, server: example.com, request: "GET / HTTP/1.1", host: "example.com"

Das Log-Level ist hier [warn] wegen der Direktive limit_req_log_level warn. Stellen Sie sicher, dass Ihre error_log-Direktive das Level warn oder niedriger einschließt, sonst erscheinen diese Meldungen nicht. Die Produktions-Konfiguration mit error_log /var/log/nginx/example.error.log warn; deckt das ab.

  1. Prüfen Sie die Access-Logs auf die Variable $limit_req_status:
sudo grep "REJECTED_DRY_RUN\|DELAYED_DRY_RUN" /var/log/nginx/access.log

Die Variable $limit_req_status gibt einen der folgenden Werte zurück: PASSED, DELAYED, REJECTED, DELAYED_DRY_RUN oder REJECTED_DRY_RUN.

  1. Wenn die Raten passend aussehen, entfernen Sie die Zeile limit_req_dry_run und laden Sie neu.

Wie nehme ich vertrauenswürdige IPs vom Rate Limiting aus?

Verwenden Sie einen geo-Block, um Monitoring-Systeme, Load Balancer oder Büro-IPs vom Rate Limiting auszunehmen:

# Im http-Block
geo $limit {
    default 1;
    10.0.0.0/8      0;  # Internes Netzwerk
    192.168.0.0/16   0;  # Internes Netzwerk
    203.0.113.10     0;  # Monitoring-Server
}

map $limit $limit_key {
    0 "";
    1 $binary_remote_addr;
}

limit_req_zone $limit_key zone=general:10m rate=10r/s;

Wenn $limit_key ein leerer String ist, überspringt Nginx das Rate Limiting für diesen Request vollständig. IPs, die dem geo-Block entsprechen, erhalten $limit = 0, was auf einen leeren Schlüssel abgebildet wird.

Wenn Sie möchten, dass Allowlisted-IPs eine höhere Rate statt keiner Begrenzung bekommen:

limit_req_zone $limit_key zone=general:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=trusted:1m rate=100r/s;

server {
    limit_req zone=general burst=20 nodelay;
    limit_req zone=trusted burst=100 nodelay;
}

Alle IPs werden von trusted erfasst, aber nur nicht gelistete IPs von general. Das restriktivste Limit gilt, sodass Allowlisted-IPs auf 100 r/s begrenzt sind, alle anderen auf 10 r/s.

Wie sperre ich Wiederholungstäter mit fail2ban?

Rate Limiting lehnt einzelne Requests ab, aber hartnäckige Angreifer kommen immer wieder. fail2ban überwacht das Nginx-Error-Log und sperrt IPs auf Firewall-Ebene nach wiederholten Verstößen.

Installieren Sie fail2ban, falls noch nicht geschehen:

sudo apt update && sudo apt install -y fail2ban
sudo systemctl enable --now fail2ban
sudo systemctl status fail2ban
 fail2ban.service - Fail2Ban Service
     Loaded: loaded (/usr/lib/systemd/system/fail2ban.service; enabled; preset: enabled)
     Active: active (running) since Wed 2026-03-19 14:30:00 UTC; 2s ago

fail2ban enthält einen eingebauten Filter nginx-limit-req. Die Regex des Filters matcht Zeilen wie:

limiting requests, excess: 1.532 by zone "general", client: 203.0.113.50

Erstellen Sie die Jail-Konfiguration. Bearbeiten Sie niemals .conf-Dateien direkt; verwenden Sie .local-Overrides:

sudo nano /etc/fail2ban/jail.local
[nginx-limit-req]
enabled  = true
port     = http,https
filter   = nginx-limit-req
logpath  = /var/log/nginx/error.log
maxretry = 10
findtime = 60
bantime  = 600

Damit wird eine IP für 10 Minuten gesperrt nach 10 Rate-Limit-Verstößen innerhalb von 60 Sekunden.

Für eskalierende Sperren fügen Sie ein zweites Jail in derselben Datei hinzu:

[nginx-limit-req-repeat]
enabled  = true
port     = http,https
filter   = nginx-limit-req
logpath  = /var/log/nginx/error.log
maxretry = 30
findtime = 3600
bantime  = 86400

Das erste Jail fängt kurze Bursts ab (10 Treffer in einer Minute = 10-Minuten-Sperre). Das zweite fängt hartnäckige Wiederholungstäter (30 Treffer in einer Stunde = 24-Stunden-Sperre).

Starten Sie fail2ban neu und prüfen Sie den Jail-Status:

sudo systemctl restart fail2ban
sudo fail2ban-client status nginx-limit-req

Auf Debian 12 und älteren Systemen sieht die Ausgabe so aus:

Status for the jail: nginx-limit-req
|- Filter
|  |- Currently failed:	0
|  |- Total failed:	0
|  `- File list:	/var/log/nginx/error.log
`- Actions
   |- Currently banned:	0
   |- Total banned:	0
   `- Banned IP list:

Auf Ubuntu 24.04 verwendet fail2ban standardmäßig das systemd-Journal-Backend (backend = auto löst zu systemd auf). Die Ausgabe zeigt Journal matches: statt File list::

Status for the jail: nginx-limit-req
|- Filter
|  |- Currently failed:	0
|  |- Total failed:	0
|  `- Journal matches:	_SYSTEMD_UNIT=nginx.service + _COMM=nginx
`- Actions
   |- Currently banned:	0
   |- Total banned:	0
   `- Banned IP list:

Beide Backends funktionieren. Das Journal-Backend liest dieselben Nginx-Log-Meldungen über systemd. Wenn Sie dateibasierte Überwachung bevorzugen, fügen Sie backend = pyinotify zum Jail-Abschnitt hinzu.

Um eine IP während des Testens manuell zu entsperren:

sudo fail2ban-client set nginx-limit-req unbanip 203.0.113.50

Das Jail-Log finden Sie unter:

sudo journalctl -u fail2ban -f

Wie überprüfe ich, ob Rate Limiting funktioniert?

Testen Sie von einem externen Rechner. Testen Sie nie von localhost, da 127.0.0.1 in Ihrer Allowlist stehen könnte.

Schnelltest mit einer curl-Schleife:

for i in $(seq 1 20); do
    curl -s -o /dev/null -w "%{http_code}\n" https://example.com/
done

Bei einer Rate von 10r/s und burst=20 nodelay geben die ersten 21 Requests 200 zurück. Sobald der Burst aufgebraucht ist, wechseln die Antworten zu 429.

Lasttest mit wrk:

sudo apt install -y wrk
wrk -t2 -c10 -d10s https://example.com/
Running 10s test @ https://example.com/
  2 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     5.23ms    2.11ms  28.44ms   75.32%
    Req/Sec     1.02k   121.33     1.34k    68.00%
  20384 requests in 10.01s, 15.22MB read
  Non-2xx or 3xx responses: 18241
Requests/sec:   2036.36
Transfer/sec:      1.52MB

Der Zähler Non-2xx or 3xx responses zeigt, wie viele Requests Nginx limitiert hat. Hier erhielten 18.241 von 20.384 Requests einen 429.

Prüfen Sie das Error-Log während des Tests:

sudo tail -f /var/log/nginx/error.log
2026/03/19 14:45:12 [warn] 1234#1234: *890 limiting requests, excess: 9.876 by zone "general", client: 203.0.113.50, server: example.com, request: "GET / HTTP/1.1", host: "example.com"

Der excess-Wert zeigt, wie weit über dem Limit der Request lag. Höhere Werte weisen auf aggressiveren Traffic hin.

Vollständige Produktions-Konfiguration

Die komplette Rate-Limiting-Konfiguration mit allen drei Schichten:

# /etc/nginx/conf.d/rate-limiting.conf

# --- Allowlist ---
geo $limit {
    default 1;
    10.0.0.0/8      0;
    192.168.0.0/16   0;
    # Ihre Monitoring-/Büro-IPs hier eintragen
}

map $limit $limit_key {
    0 "";
    1 $binary_remote_addr;
}

# --- Request-Rate-Zonen ---
limit_req_zone $limit_key zone=general:10m rate=10r/s;
limit_req_zone $limit_key zone=login:10m rate=1r/s;
limit_req_zone $limit_key zone=api:10m rate=30r/s;

# --- Verbindungszone ---
limit_conn_zone $binary_remote_addr zone=addr:10m;

# --- Antwortcodes und Protokollierung ---
limit_req_status 429;
limit_conn_status 429;
limit_req_log_level warn;
limit_conn_log_level warn;

# --- Access-Log mit Rate-Limit-Status ---
log_format ratelimit '$remote_addr - $remote_user [$time_local] '
                     '"$request" $status $body_bytes_sent '
                     '"$http_referer" "$http_user_agent" '
                     'rate_limit=$limit_req_status';
# /etc/nginx/sites-available/example.com

server {
    listen 80;
    server_name example.com;

    access_log /var/log/nginx/example.access.log ratelimit;
    error_log /var/log/nginx/example.error.log warn;

    # Globale Limits
    limit_req zone=general burst=20 nodelay;
    limit_conn addr 30;

    # Benutzerdefinierte 429-Seite
    error_page 429 /429.html;
    location = /429.html {
        root /var/www/error;
        internal;
        add_header Retry-After 5 always;
    }

    location /login {
        limit_req zone=login burst=3 nodelay;
        limit_conn addr 5;
        proxy_pass http://127.0.0.1:3000;
    }

    location /api/ {
        limit_req zone=api burst=50 delay=30;
        limit_conn addr 20;
        proxy_pass http://127.0.0.1:3000;
    }

    location / {
        proxy_pass http://127.0.0.1:3000;
    }
}
# /etc/fail2ban/jail.local

[nginx-limit-req]
enabled  = true
port     = http,https
filter   = nginx-limit-req
logpath  = /var/log/nginx/example.error.log
maxretry = 10
findtime = 60
bantime  = 600

[nginx-limit-req-repeat]
enabled  = true
port     = http,https
filter   = nginx-limit-req
logpath  = /var/log/nginx/example.error.log
maxretry = 30
findtime = 3600
bantime  = 86400

Nach dem Anlegen aller Konfigurationsdateien:

sudo nginx -t && sudo systemctl reload nginx
sudo systemctl restart fail2ban

Für ein umfassenderes Sicherheits-Setup einschließlich Headers, TLS und weiterer Härtungsmaßnahmen, siehe.

Direktiven-Referenz

Direktive Kontext Standard Seit
limit_req_zone http - 0.7.21
limit_req http, server, location - 0.7.21
limit_req_status http, server, location 503 1.3.15
limit_req_log_level http, server, location error 0.8.18
limit_req_dry_run http, server, location off 1.17.1
limit_conn_zone http - 1.1.8
limit_conn http, server, location - 0.7.21
limit_conn_status http, server, location 503 1.3.15
limit_conn_log_level http, server, location error 0.8.18
limit_conn_dry_run http, server, location off 1.17.6

Fehlerbehebung

Rate Limiting funktioniert überhaupt nicht: Prüfen Sie, ob limit_req_zone im http-Block steht, nicht in einem server-Block. Zonen müssen definiert werden, bevor sie referenziert werden. Wenn Ihre Konfiguration include-Direktiven verwendet, stellen Sie sicher, dass die Zonendatei vor den Server-Blöcken eingebunden wird.

Legitime Benutzer bekommen 429: Senken Sie die rate, erhöhen Sie den burst, oder wechseln Sie von keinem Burst zu burst=N nodelay. Nutzen Sie den dry_run-Modus, um reale Traffic-Muster zu messen, bevor Sie Limits festlegen. Prüfen Sie, ob HTTP/2-Multiplexing die limit_conn-Zähler aufbläht.

fail2ban sperrt nicht: Bestätigen Sie, dass der logpath mit dem tatsächlichen Speicherort der Nginx-Error-Logs übereinstimmt. Prüfen Sie, ob limit_req_log_level auf warn oder error gesetzt ist (Standard). Überprüfen Sie, ob das Jail aktiv ist mit sudo fail2ban-client status nginx-limit-req. Wenn Sie von localhost testen, beachten Sie, dass fail2ban die eigene Server-IP standardmäßig ignoriert (ignoreself = true). Testen Sie von einer externen Maschine.

Rate-Limit-Meldungen erscheinen nicht im Error-Log: Die Direktive error_log steht standardmäßig auf Level error, was Meldungen auf warn-Level von limit_req_log_level warn ausfiltert. Setzen Sie error_log /var/log/nginx/error.log warn; in Ihrem Server-Block, um Rate-Limit-Ereignisse zu sehen.

Zonenspeicher erschöpft: Eine 10m-Zone fasst etwa 160.000 IPv4-Zustände. Wenn Sie could not allocate node in den Logs sehen, vergrößern Sie die Zone. Überwachen Sie die Zonenauslastung über die Zeit mit $limit_req_status in Ihren Access-Logs.

Hinter einem Load Balancer oder CDN: Wenn Nginx nur die IP des Load Balancers sieht, gilt Rate Limiting für diese eine IP. Verwenden Sie $http_x_forwarded_for oder $realip_remote_addr als Zonenschlüssel statt $binary_remote_addr. Sie müssen auch set_real_ip_from mit dem IP-Bereich des Load Balancers konfigurieren. Vertrauen Sie X-Forwarded-For nur von bekannten Proxies, da Clients den Header fälschen können.

Logs sind Ihr wichtigstes Debugging-Werkzeug:

# Rate-Limit-Ereignisse in Echtzeit verfolgen
sudo tail -f /var/log/nginx/error.log | grep "limiting"

# fail2ban-Aktionen prüfen
sudo journalctl -u fail2ban -f