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_conn
Direktive 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_conn
auf 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_conn
innerhalb des location ~ \.php$
Blocks ignorieren:
- 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. - 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 imlocation ~ \.php$
Block ignoriert. - Wenn ich die
conn_limit
Direktive auf Serverebene lösche,location ~ \.php$
funktioniert die Direktive im Block plötzlich! - Noch verwirrender: Wenn ich die
conn_limit
Direktive zumlocation /
Blockieren hinzufüge, überschreibt sie korrekt die globale!
Vielleicht liegt das Problem in try_files
der Direktive oder in mehreren Weiterleitungen? Ich wäre sehr dankbar, wenn mir jemand erklären könnte, warum die conn_limit
Direktive nicht wie erwartet überschrieben wird.
Antwort1
Danke an @AlexeyTen, ich hoffe, die Frage beantworten zu können.
Wichtig sind zwei Punkte:
- Die
limit_conn
Anweisung wird pro Anfrage nur einmal verarbeitet! - Diese Anweisungen werden genau dann von der vorherigen Ebene übernommen, wenn
limit_conn
auf 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_conn
werden 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_conn
auf dieser server
Ebene, sondern wartet, um nach einem passenden Standort zu suchen location /
. Auf dieser Ebene gibt es jedoch keine limit_conn
Direktive, also verarbeitet nginx die auf dieser server
Ebene. Danach limit_conn
werden alle Direktiven ignoriert, da sie bereits verarbeitet wurden. Das erklärt meine Tests 1-3.
In Test 4 findet nginx eine limit_conn
Direktive an Ort und Stelle location /
und verarbeitet sie, aber wieder wird an Ort und Stelle location @rewrite
keine limit_conn
gefunden, also wird die Direktive an location /
verarbeitet. Auch hier ignorieren wir den location ~ \.php$
Block.