Nginx limit_conn наследование

Nginx limit_conn наследование

Я пытаюсь защитить Drupal, работающий на Nginx, от простого DDoS с помощью limit_conn и limit_req. Но я столкнулся со странным поведением при наследовании 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 для всех запросов и до 4 для php-бэкэнда.(В этом примере я изменил соединение 4 на 1, чтобы его было легче запустить)

Документация Nginx по адресуhttp://nginx.org/en/docs/http/ngx_http_limit_conn_module.html#limit_connговорится, что:

limit_connЭти директивы наследуются от предыдущего уровня тогда и только тогда, когда на текущем уровне нет директив.

Но в моих тестах происходит что-то странное. Похоже, nginx игнорирует директиву limit_connвнутри location ~ \.php$блока:

  1. Когда я тестирую эту конфигурацию с 5 одновременными подключениями ab -n 100 -c 5 http://test.dev/, блокировки не происходит. Как только я увеличиваю лимит
    до 11, -c 11nginx начинает блокировать запросы.
  2. Если я изменю глобальный лимит подключений с 10 до 5, nginx ограничит более 6 подключений ( -c 6) - похоже, директива в location ~ \.php$блоке игнорируется.
  3. Если я удаляю conn_limitдирективу на уровне сервера, директива в location ~ \.php$блоке внезапно начинает работать!
  4. Еще более запутанно: если я добавляю conn_limitдирективу location /block, она корректно перезаписывает глобальную!

Может проблема в 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уровне, а ждет, чтобы посмотреть на соответствующее местоположение location /. Но на этом уровне нет limit_connдирективы, поэтому nginx обрабатывает ту, что на serverуровне. После этого все limit_connдирективы игнорируются, потому что она уже была обработана. Это объясняет мои тесты 1-3.

В тесте 4 nginx находит limit_connдирективу в location location /и обрабатывает ее, но снова на location location @rewriteno не limit_connнайдено, поэтому обрабатывается директива at location /. Опять же, мы игнорируем location ~ \.php$блок.

Связанный контент