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), wrk oder curl

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 in server- oder location-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

Featurelimit_reqlimit_connExterner WAF (Cloudflare/ModSecurity)
SteuertAnfragerate (Anf./s)Gleichzeitige VerbindungenBeides + Layer-7-Muster
AlgorithmusLeaky BucketVerbindungszählerVariiert (ML, Signaturen)
GranularitätPro Schlüssel (IP, Header usw.)Pro SchlüsselPro Regel, Geo, ASN
Performance-AuswirkungMinimalMinimalLeichte Latenz hinzugefügt
DDoS-WirksamkeitGut gegen L7-FloodsGut gegen SlowlorisAm besten gegen volumetrische Angriffe
KonfigurationNur Nginx-KonfigurationNur Nginx-KonfigurationSeparater Dienst/Agent
KostenKostenlosKostenlosKostenloser 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_addr die Proxy-IP — nicht die des Clients. Verwenden Sie set_real_ip_from und real_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/s mit burst=20 erlaubt nicht 30 Anfragen/Sekunde. Es erlaubt eine Burst-Warteschlange von 20 Anfragen, die mit 10/s abfließen. Ohne nodelay erleben 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_log fü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 on und Tools wie ab oder wrk, bevor Sie in der Produktion durchsetzen.
  • Berücksichtigen Sie Proxys und CDNs, indem Sie real_ip_header konfigurieren, um die tatsächliche Client-IP zu identifizieren.
  • Kombinieren Sie Nginx Rate Limiting mit Fail2ban und einem externen WAF für eine gestaffelte Verteidigung.

Verwandte Artikel