Nginx Rate Limiting – Schutz vor Bots und Missbrauch

Wenn Anfragen aus dem Ruder laufen, hat das selten mit echten Nutzern zu tun. Meist sind es Bots, Scraper oder schlicht fehlerhafte Clients, die deinen Server stressen. Das Ergebnis sind hohe Latenzen, Fehler und genervte Besucher. Mit Nginx Rate Limiting stellst du sicher, dass jede Quelle nur angemessen viele Anfragen senden darf.

Das Gute: Du brauchst dafür keine extra Tools. Nginx bringt alles mit, um Anfrageraten zu begrenzen, gleichzeitige Verbindungen zu drosseln und im Notfall sauber abzulehnen. In diesem Guide zeige ich dir, wie du Limits verständnisvoll setzt, klassische Stolpersteine vermeidest und dein Setup Schritt für Schritt aufbaust.

Grundlagen: Was Rate Limiting leistet

Rate Limiting begrenzt, wie viele Requests pro Zeit oder gleichzeitige Verbindungen eine Quelle haben darf. Ziele sind Verfügbarkeit, Kostenkontrolle und Fairness. Wichtig ist die Schlüsselwahl: Du kannst pro IP, pro API-Key, pro Benutzer oder pro Route limitieren. Falsche Schlüssel führen zu falschen Sperren oder zu laschen Regeln.

Die Bausteine in Nginx

limit_req_zone und limit_req

Mit limit_req_zone definierst du eine Zone mit Schlüssel und Rate. limit_req wendest du später im server oder location an.
Beispielschlüssel: $binary_remote_addr für IP-basiert oder $http_authorization bzw. ein JWT-Claim für logische Nutzer.

burst und nodelay

Kurzfristige Spitzen lassen sich mit burst auffangen. Damit dürfen einige Requests über das Limit, werden aber gepuffert. nodelay schaltet Pufferung ab und lehnt Überschuss sofort ab. Das ergibt klare Grenzen und stabile Latenz.

limit_conn_zone und limit_conn

Während limit_req Raten drosselt, begrenzt limit_conn die gleichzeitigen Verbindungen. Das schützt z. B. vor vielen offenen Downloads oder Slowloris-Mustern.

Konfiguration Schritt für Schritt

1. Schlüssel und Zonen definieren

Im http Block:

# 1 Request pro Sekunde je IP, kurzzeitige Spitzen erlauben wir später mit burst
limit_req_zone $binary_remote_addr zone=ip_zone:10m rate=1r/s;

# Gleichzeitige Verbindungen je IP zählen
limit_conn_zone $binary_remote_addr zone=ip_conn:10m;

Tipp: Hinter einem Load Balancer musst du die echte Client-IP korrekt setzen.

# nur wenn der Proxy vertrauenswürdig ist
set_real_ip_from 10.0.0.0/8;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

2. Limits anwenden – API Beispiel

server {
  listen 443 ssl;
  server_name api.beispiel.de;

  location /v1/ {
    limit_req zone=ip_zone burst=10 nodelay;  # sofort 429 bei Überschuss
    limit_conn ip_conn 10;                    # max 10 gleichzeitige Verbindungen je IP
    proxy_pass http://api_backend;
  }
}

Warum so: burst=10 fängt kurze Peaks ab. nodelay vermeidet Warteschlangen, die Latenz und Memory treiben.

3. Statisch anders behandeln

Assets können großzügiger sein:

location /assets/ {
  limit_req zone=ip_zone burst=20;
  limit_conn ip_conn 20;
  expires 7d;
  try_files $uri =404;
}

4. Saubere Fehlerrückgabe mit Hinweisen

# eigene 429 Seite
error_page 429 = @too_many;

location @too_many {
  add_header Retry-After 30 always;
  return 429 "Too Many Requests - bitte später erneut versuchen\n";
}

Wichtig: Retry-After signalisiert Clients, wann ein erneuter Versuch sinnvoll ist.

5. Whitelists und Health Checks

# interne Monitoring-IPs von Limits ausnehmen
geo $whitelist {
  default 0;
  192.0.2.10 1;
  198.51.100.0/24 1;
}

map $whitelist $limit_bypass {
  1  "";
  0  "ip_zone";
}

location /healthz {
  # keine Limits für Health Checks
  proxy_pass http://api_backend;
}

location /v1/ {
  if ($limit_bypass) { } # Platzhalter
  limit_req zone=$limit_bypass burst=10 nodelay;
  limit_conn ip_conn 10;
  proxy_pass http://api_backend;
}

Einfacher geht es je nach Setup auch mit separaten Serverblöcken für interne Pfade.

Testen wie ein Profi

Mit curl

# mehrere schnelle Anfragen auslösen
for i in {1..15}; do curl -s -o /dev/null -w "%{http_code}\n" https://api.beispiel.de/v1/ping; done

Du solltest 200 für die ersten Anfragen sehen und danach 429.

Mit hey oder ab

Tools wie hey oder ab erzeugen Last und zeigen, ob p95 stabil bleibt:

hey -z 10s -q 5 https://api.beispiel.de/v1/ping

Logging und Monitoring

Aktiviere in deinem Logformat Limit-Variablen:

log_format main '$remote_addr - $request - $status - $request_time - '
                'req_status:$limit_req_status conn:$connections_active';
access_log /var/log/nginx/access.log main;

$limit_req_status zeigt PASSED, DELAYED, REJECTED. So erkennst du, ob Limits greifen oder zu scharf sind.

Typische Fehler und wie du sie vermeidest

  • Falsche IP hinter Proxies: Ohne real_ip-Konfiguration limitierst du den Load Balancer statt der Clients.
  • Zu harte Defaults: Starte mit 1r/s plus burst, beobachte, dann nachschärfen.
  • Warteschlangen bauen: Zu viele burst ohne nodelay erhöhen Latenz. Für APIs lieber nodelay.
  • Alles gleich behandeln: Trenne API, Assets und Admin mit eigenen Limits.
  • Keine Kommunikation: Sende 429 mit Retry-After und klarer Fehlermeldung.
  • Nur Rate begrenzen: Vergiss limit_conn nicht, sonst können Verbindungen offen bleiben.

Werte sinnvoll wählen

  • Öffentliche API: 1-5 r/s je IP, burst 5-20, limit_conn 5-20.
  • Interne Tools: großzügiger, aber mit Whitelist.
  • Downloads: stärker über limit_conn steuern, Rate höher.
    Je nach Publikum lohnt ein zweiter Schlüssel wie API-Key:
map $http_x_api_key $ratelimit_key { default $binary_remote_addr; ~.+ $http_x_api_key; }
limit_req_zone $ratelimit_key zone=key_zone:20m rate=5r/s;

So werden legitime Nutzer hinter einer NAT-IP nicht unnötig gebremst.

Kompakte Beispielkonfiguration

http {
  set_real_ip_from 10.0.0.0/8;
  real_ip_header X-Forwarded-For;
  real_ip_recursive on;

  limit_req_zone $binary_remote_addr zone=ip_zone:10m rate=1r/s;
  limit_conn_zone $binary_remote_addr zone=ip_conn:10m;

  log_format main '$remote_addr "$request" $status $request_time req:$limit_req_status';
  access_log /var/log/nginx/access.log main;

  server {
    listen 443 ssl;
    server_name api.beispiel.de;

    location /v1/ {
      limit_req zone=ip_zone burst=10 nodelay;
      limit_conn ip_conn 10;
      proxy_pass http://api_backend;
    }

    error_page 429 = @too_many;
    location @too_many {
      add_header Retry-After 30 always;
      return 429 "Too Many Requests - bitte später erneut versuchen\n";
    }
  }
}

Fazit

Nginx Rate Limiting ist ein einfaches, starkes Mittel gegen Bots und Missbrauch. Mit klaren Schlüsseln, real_ip hinter Proxies, passenden limit_req und limit_conn Werten sowie ehrlichen 429-Antworten hältst du dein System stabil und fair. Starte konservativ, messe, justiere burst und nodelay je Route und dokumentiere deine Entscheidungen. So bleibt deine Plattform performant und robust, auch wenn es mal stürmisch wird.

0 Kommentare

Hinterlasse einen Kommentar

An der Diskussion beteiligen?
Hinterlasse uns deinen Kommentar!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert