Rate Limiting ist eine der effektivsten ersten Verteidigungslinien gegen DDoS-Angriffe, Brute-Force-Anmeldeversuche und API-Missbrauch. Nginx enthält zwei leistungsstarke integrierte Module — limit_req und limit_conn — mit denen Sie eingehenden Datenverkehr drosseln können, ohne Drittanbieter-Software zu installieren. In dieser Anleitung konfigurieren Sie beide Module mit produktionsreifen Beispielen, setzen vertrauenswürdige IPs auf die Whitelist und testen alles vor dem produktiven Einsatz.
Voraussetzungen
- Nginx 1.18+ installiert auf einem Linux-Server (Ubuntu/Debian oder RHEL/CentOS)
- Root- oder Sudo-Zugriff
- Grundlegende Vertrautheit mit Nginx-Server-Blöcken und Konfigurationssyntax
- Ein Tool für Lasttests:
ab(Apache Bench),wrkodercurl
Nginx Rate Limiting verstehen
Das limit_req-Modul von Nginx implementiert den Leaky-Bucket-Algorithmus. Stellen Sie sich einen Eimer mit einem kleinen Loch am Boden vor: Wasser (Anfragen) strömt mit unterschiedlichen Raten hinein, fließt aber mit einer festen Rate ab. Wenn der Eimer überläuft, werden überschüssige Wassermengen (Anfragen) abgelehnt.
Zwei Schlüsselkonzepte bestimmen die Konfiguration:
- Zone: Ein gemeinsam genutzter Speicherbereich, der Anfragezählungen pro Schlüssel (üblicherweise Client-IP) verfolgt. Wird einmal im
http-Block definiert und inserver- oderlocation-Blöcken referenziert. - Rate: Der erlaubte Durchsatz, ausgedrückt als Anfragen pro Sekunde (
r/s) oder pro Minute (r/m). Nginx konvertiert intern alles in Pro-Sekunde-Granularität.
Das limit_conn-Modul funktioniert anders — es begrenzt die Anzahl der gleichzeitig geöffneten Verbindungen von einem einzelnen Schlüssel, anstatt die Anfragerate.
Anfrage-Rate-Limiting konfigurieren
Beginnen Sie mit der Definition von Zonen im http-Block von /etc/nginx/nginx.conf:
http {
# Allgemeine Zone: 10 Anfragen/Sekunde pro IP, 10 MB gemeinsamer Speicher
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
# Strenge Zone für Login-Endpunkte: 1 Anfrage/Sekunde pro IP
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
# 429 statt dem Standard 503 zurückgeben
limit_req_status 429;
}
Die Variable $binary_remote_addr speichert Client-IPs in einem kompakten Binärformat — 10 MB fassen ungefähr 160.000 Adressen.
Wenden Sie diese Zonen nun in Ihrem Server-Block an:
server {
listen 80;
server_name example.com;
# Allgemeines Rate Limit für alle Anfragen
location / {
limit_req zone=general burst=20 nodelay;
proxy_pass http://backend;
}
# Strenges Limit auf der Login-Seite
location /wp-login.php {
limit_req zone=login burst=3 nodelay;
proxy_pass http://backend;
}
# Benutzerdefinierte 429-Fehlerseite
error_page 429 /rate_limit.html;
location = /rate_limit.html {
internal;
return 429 '{"error": "Too many requests. Please retry after a few seconds."}';
default_type application/json;
}
}
Der burst-Parameter definiert, wie viele überschüssige Anfragen in die Warteschlange gestellt werden können, bevor Nginx beginnt, Anfragen abzulehnen. Mit nodelay werden Burst-Anfragen sofort verarbeitet, anstatt zeitversetzt — dies bietet eine bessere Benutzererfahrung bei legitimen Datenverkehrsspitzen.
Verbindungslimits konfigurieren
Verbindungsbegrenzung verhindert, dass eine einzelne IP zu viele Sockets gleichzeitig offen hält, was der Kernmechanismus hinter Slowloris-artigen Angriffen ist:
http {
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_conn_status 429;
}
server {
# Maximal 10 gleichzeitige Verbindungen pro IP
limit_conn addr 10;
# Bandbreite pro Verbindung begrenzen (optional)
limit_rate 100k;
location /downloads/ {
limit_conn addr 2;
limit_rate 50k;
}
}
Rate-Limiting-Vergleich
| Feature | limit_req | limit_conn | Externer WAF (Cloudflare/ModSecurity) |
|---|---|---|---|
| Steuert | Anfragerate (Anf./s) | Gleichzeitige Verbindungen | Beides + Layer-7-Muster |
| Algorithmus | Leaky Bucket | Verbindungszähler | Variiert (ML, Signaturen) |
| Granularität | Pro Schlüssel (IP, Header usw.) | Pro Schlüssel | Pro Regel, Geo, ASN |
| Performance-Auswirkung | Minimal | Minimal | Leichte Latenz hinzugefügt |
| DDoS-Wirksamkeit | Gut gegen L7-Floods | Gut gegen Slowloris | Am besten gegen volumetrische Angriffe |
| Konfiguration | Nur Nginx-Konfiguration | Nur Nginx-Konfiguration | Separater Dienst/Agent |
| Kosten | Kostenlos | Kostenlos | Kostenloser Tarif oder kostenpflichtig |
Für die meisten Server bietet die Kombination von limit_req + limit_conn lokal mit einem externen WAF eine gestaffelte Verteidigung.
Praxisszenario
Sie haben einen Produktionsserver mit WordPress hinter Nginx. Ihre Zugriffsprotokolle zeigen Tausende von POST-Anfragen, die /wp-login.php und /xmlrpc.php von rotierenden IPs treffen — ein verteilter Brute-Force-Angriff. Die CPU-Auslastung steigt stark an und legitime Benutzer erleben Timeouts.
Hier ist eine Produktionskonfiguration, die dieses Problem löst:
http {
limit_req_zone $binary_remote_addr zone=wp_login:10m rate=1r/s;
limit_req_zone $binary_remote_addr zone=xmlrpc:10m rate=1r/m;
limit_req_zone $binary_remote_addr zone=general:10m rate=30r/s;
limit_req_status 429;
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
}
server {
listen 443 ssl;
server_name example.com;
limit_conn conn_limit 15;
location / {
limit_req zone=general burst=50 nodelay;
proxy_pass http://127.0.0.1:8080;
}
location = /wp-login.php {
limit_req zone=wp_login burst=3 nodelay;
proxy_pass http://127.0.0.1:8080;
}
# xmlrpc.php fast vollständig blockieren — 1 Anfrage pro Minute
location = /xmlrpc.php {
limit_req zone=xmlrpc burst=1 nodelay;
proxy_pass http://127.0.0.1:8080;
}
}
Nach dem Anwenden dieser Konfiguration und dem Ausführen von nginx -t && systemctl reload nginx erhält der Brute-Force-Datenverkehr 429-Antworten, während sich legitime Benutzer weiterhin normal authentifizieren können.
Vertrauenswürdige IPs auf die Whitelist setzen
Monitoring-Systeme, Health-Checks und Büronetzwerke sollten Rate Limits umgehen. Verwenden Sie das geo-Modul, um eine Whitelist zu erstellen:
http {
geo $rate_limit_key {
default $binary_remote_addr;
10.0.0.0/8 ""; # Internes Netzwerk
192.168.1.0/24 ""; # Büronetzwerk
203.0.113.50 ""; # Monitoring-Server
}
# Leerer Schlüssel = kein Tracking = kein Rate Limit
limit_req_zone $rate_limit_key zone=general:10m rate=10r/s;
}
Wenn $rate_limit_key zu einem leeren String aufgelöst wird, überspringt Nginx das Rate-Limit-Tracking für diese Anfrage vollständig.
Rate Limits testen
Testen Sie immer in einer Staging-Umgebung, bevor Sie in die Produktion deployen. Verwenden Sie limit_req_dry_run on, um Verstöße zu protokollieren, ohne zu blockieren:
location / {
limit_req zone=general burst=20 nodelay;
limit_req_dry_run on; # Nur protokollieren, nicht blockieren
}
Erzeugen Sie dann Datenverkehr mit Apache Bench:
# 100 Anfragen mit 10 gleichzeitigen Verbindungen senden
ab -n 100 -c 10 https://staging.example.com/
# Prüfen, wie viele rate-begrenzt wurden
grep "limiting requests" /var/log/nginx/error.log | wc -l
# 429-Antworten im Zugriffsprotokoll prüfen
awk '$9 == 429' /var/log/nginx/access.log | wc -l
Oder verwenden Sie wrk für anhaltende Lasttests:
wrk -t4 -c50 -d30s https://staging.example.com/
Sobald Sie mit den Schwellenwerten zufrieden sind, entfernen Sie die limit_req_dry_run-Direktive und laden Sie Nginx neu.
Fallstricke und Sonderfälle
- Clients hinter CDN/Proxy: Wenn Nginx hinter Cloudflare, einem Load Balancer oder einem Reverse Proxy steht, ist
$binary_remote_addrdie Proxy-IP — nicht die des Clients. Verwenden Sieset_real_ip_fromundreal_ip_header, um die tatsächliche Client-IP zu extrahieren:
set_real_ip_from 173.245.48.0/20; # Cloudflare-IP-Bereich
set_real_ip_from 103.21.244.0/22;
real_ip_header CF-Connecting-IP;
- Gemeinsam genutzte IPs (NAT/Unternehmen): Aggressive Rate Limits können ganze Büros hinter einer einzelnen NAT-IP blockieren. Setzen Sie vernünftige Burst-Werte und setzen Sie bekannte Unternehmens-IP-Bereiche auf die Whitelist.
- Zonen-Speichererschöpfung: Wenn der Zone der Speicher ausgeht, gibt Nginx 503 für alle neuen Schlüssel zurück. Überwachen Sie die Zonennutzung und dimensionieren Sie entsprechend — 1 MB fasst ungefähr 16.000 IP-Adressen.
- Rate vs. Burst Missverständnis: Eine Rate von
10r/smitburst=20erlaubt nicht 30 Anfragen/Sekunde. Es erlaubt eine Burst-Warteschlange von 20 Anfragen, die mit 10/s abfließen. Ohnenodelayerleben Anfragen in der Warteschlange eine künstliche Verzögerung. - Log-Rauschen: Rate Limiting bei hohem Datenverkehr füllt Fehlerprotokolle schnell. Verwenden Sie ein separates
error_logfür rate-begrenzte Locations oder passen Sie die Protokollierungsebenen an.
Zusammenfassung
- Verwenden Sie
limit_req, um Anfrageraten mit dem Leaky-Bucket-Algorithmus zu drosseln — ideal für Login-Seiten, APIs und allgemeinen Flutschutz. - Verwenden Sie
limit_conn, um gleichzeitige Verbindungen pro IP zu begrenzen — wirksam gegen Slowloris- und Ressourcenerschöpfungsangriffe. - Ändern Sie immer den Standard-Statuscode auf 429 mit
limit_req_status 429. - Setzen Sie interne IPs mit dem
geo-Modul auf die Whitelist, damit Monitoring und Health-Checks niemals blockiert werden. - Testen Sie mit
limit_req_dry_run onund Tools wieaboderwrk, bevor Sie in der Produktion durchsetzen. - Berücksichtigen Sie Proxys und CDNs, indem Sie
real_ip_headerkonfigurieren, um die tatsächliche Client-IP zu identifizieren. - Kombinieren Sie Nginx Rate Limiting mit Fail2ban und einem externen WAF für eine gestaffelte Verteidigung.