Nginx limit_conn-Vererbung

Nginx limit_conn-Vererbung

Ich versuche, Drupal, das auf Nginx läuft, mit limit_conn und limit_req vor einfachem DDoS zu schützen. Aber ich habe ein seltsames Verhalten bei der Vererbung der limit_connDirektive festgestellt, das ich nicht erklären kann.

Ich habe meine Nginx-Konfiguration (1.8.0) auf dieses absolute Minimum reduziert, das das Problem zeigt:

limit_conn_zone $binary_remote_addr zone=perip:10m;

server {
    server_name test.dev;
    root /var/nginx/drupal; ## <-- Your only path reference.

    #Allow not more than 10 simultaneous connections from one address.
    limit_conn perip  10;

    location / {
        #limit_conn perip 1;
        # This is cool because no php is touched for static content
        try_files $uri @rewrite;
    }

    location @rewrite {
        # Clean URLs are handled in drupal_environment_initialize().
        rewrite ^ /index.php;
    }

    location ~ \.php$ {
        #Allow not more than 1 simultaneous *connection_to_PHP* from one address.
        limit_conn perip 1; 

        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        include fastcgi.conf;
        fastcgi_intercept_errors on;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
    }
}

Wie Sie sehen, möchte ich die Anzahl der gleichzeitigen Verbindungen für alle Anfragen auf 10 und für das PHP-Backend auf 4 begrenzen.(In diesem Beispiel habe ich die Verbindung 4 auf 1 geändert, damit sie leichter auszulösen ist)

Die Nginx-Dokumentation unterhttp://nginx.org/en/docs/http/ngx_http_limit_conn_module.html#limit_connbesagt, dass:

Diese Anweisungen werden genau dann von der vorherigen Ebene übernommen, wenn limit_connauf der aktuellen Ebene keine Anweisungen vorhanden sind.

Aber bei meinen Tests passiert etwas Seltsames, es sieht so aus, als würde Nginx die Anweisung limit_conninnerhalb des location ~ \.php$Blocks ignorieren:

  1. Wenn ich diese Konfiguration mit 5 gleichzeitigen Verbindungen teste ab -n 100 -c 5 http://test.dev/, kommt es zu keiner Blockierung. Sobald ich das
    Limit auf 11 erhöhe -c 11, beginnt Nginx, Anfragen zu blockieren.
  2. Wenn ich das globale Verbindungslimit von 10 auf 5 ändere (Nginx begrenzt die Verbindungen auf mehr als 6 -c 6), sieht es so aus, als würde die Anweisung im location ~ \.php$Block ignoriert.
  3. Wenn ich die conn_limitDirektive auf Serverebene lösche, location ~ \.php$funktioniert die Direktive im Block plötzlich!
  4. Noch verwirrender: Wenn ich die conn_limitDirektive zum location /Blockieren hinzufüge, überschreibt sie korrekt die globale!

Vielleicht liegt das Problem in try_filesder Direktive oder in mehreren Weiterleitungen? Ich wäre sehr dankbar, wenn mir jemand erklären könnte, warum die conn_limitDirektive nicht wie erwartet überschrieben wird.

Antwort1

Danke an @AlexeyTen, ich hoffe, die Frage beantworten zu können.

Wichtig sind zwei Punkte:

  • Die limit_connAnweisung wird pro Anfrage nur einmal verarbeitet!
  • Diese Anweisungen werden genau dann von der vorherigen Ebene übernommen, wenn limit_connauf der aktuellen Ebene keine Anweisungen vorhanden sind.

TL;DR: Wenn eine Direktive vorhanden ist limit_conn, wirft nginx einen Blick in den untergeordneten Block in der Ausführungskette, wenn keine vorhanden ist limit_conn, wird der übergeordnete Block verarbeitet. Danach limit_connwerden alle anderen Direktiven ignoriert.

Ich versuche es an meinem Beispiel zu erklären:

In dem Beispiel, das ich gepostet habe, wenn ein „http://test.dev/"-Anfrage eintrifft, verarbeitet nginx sie zunächst nicht limit_connauf dieser serverEbene, sondern wartet, um nach einem passenden Standort zu suchen location /. Auf dieser Ebene gibt es jedoch keine limit_connDirektive, also verarbeitet nginx die auf dieser serverEbene. Danach limit_connwerden alle Direktiven ignoriert, da sie bereits verarbeitet wurden. Das erklärt meine Tests 1-3.

In Test 4 findet nginx eine limit_connDirektive an Ort und Stelle location /und verarbeitet sie, aber wieder wird an Ort und Stelle location @rewritekeine limit_conngefunden, also wird die Direktive an location /verarbeitet. Auch hier ignorieren wir den location ~ \.php$Block.

verwandte Informationen