我正在嘗試使用 limit_conn 和 limit_req 保護在 Nginx 上運行的 Drupal 免受簡單的 DDoS 攻擊。但我遇到了一些與limit_conn
指令繼承有關的奇怪行為,我無法解釋。
我已將 nginx (1.8.0) 配置減少到最低限度,這顯示了問題:
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;
}
}
如您所見,我希望將所有請求的同時連線數限制為 10 個,將 php 後端的同時連線數限制為 4 個。(本例中我將4連線修改為1,這樣會更容易觸發)
Nginx 文件位於http://nginx.org/en/docs/http/ngx_http_limit_conn_module.html#limit_conn指出:
limit_conn
當且僅噹噹前層級上沒有指令時,這些指令才會從上一層繼承。
但在我的測驗中發生了一些奇怪的事情,看起來 nginx 忽略了區塊limit_conn
內的指令location ~ \.php$
:
- 當我用 5 個同時連接測試此配置時
ab -n 100 -c 5 http://test.dev/
,沒有發生阻塞。一旦我將
限制提高到 11,-c 11
nginx 就會開始阻止請求。 - 如果我將全域連線限制從 10 修改為 5,nginx 會限制超過 6 個連線 (
-c 6
) - 看起來location ~ \.php$
block 中的指令被忽略。 - 如果我
conn_limit
在伺服器層級刪除該指令,則區塊中的指令location ~ \.php$
會突然開始工作! - 更令人困惑的是:如果我添加
conn_limit
要location /
阻止的指令,它會正確覆蓋全域指令!
也許問題出在try_files
指令或多個重定向?如果有人能解釋為什麼該conn_limit
指令沒有像預期的那樣被覆蓋,我將非常感激。
答案1
感謝@AlexeyTen,我希望能夠回答這個問題。
重要的是兩點:
limit_conn
每個請求僅處理該指令一次!limit_conn
當且僅噹噹前層級上沒有指令時,這些指令才會從上一層繼承。
TL;DR:如果有limit_conn
指令,nginx 會查看執行鏈中的子區塊,如果沒有limit_conn
,則處理父區塊。之後所有其他limit_conn
指令都將被忽略。
我嘗試用我的例子來解釋它:
在我發布的示例中,當“http://test.dev/「 請求到達,一開始,nginx 不是limit_conn
在server
level 處理,而是等待查找匹配的 location location /
。但是在這一 level 沒有limit_conn
指令,所以 nginx 處理該server
level 的指令。之後,所有limit_conn
指令都被忽略,因為它這解釋了我的測試1-3。
在測試 4 中,nginxlimit_conn
在 location 中找到指令location /
並處理它,但同樣,在 location 上location @rewrite
沒有找到指令,因此處理了limit_conn
指令 at 。location /
再次,我們忽略了該location ~ \.php$
區塊。