Nginx: Как ограничить скорость запросов на основе пользовательского агентам

Вопрос или проблема

Пытаюсь заставить nginx работать следующим образом:

Ограничение скорости по умолчанию 1r/s для каждого IP при использовании браузера. Ограничение скорости 10r/s для поисковых роботов bing и google. Отклонение плохих ботов.

К сожалению, google не публикует IP-адреса для googlebot, поэтому я ограничен использованием useragent.

Пока что это приближается к цели:

http { 
  # Ограничения скорости
  map $http_user_agent $uatype {
    default 'user';
    ~*(google|bing|msnbot) 'okbot';
    ~*(slurp|nastybot) 'badbot';
  }

  limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
  limit_req_zone $binary_remote_addr zone=two:10m rate=10r/s;

  ...

  server {
    ...

    location / {
      if ($uatype == 'badbot) {
        return 403;
      }

      limit_req zone=one burst=5 nodelay;
      if ($uatype != 'user') {
        limit_req zone=two burst=10 nodelay;
      }

      ...
    }

  ...
  }
}

НО – ‘if’ не разрешено использовать таким образом.

$ nginx -t

nginx: [emerg] “limit_req” directive is not allowed here in /etc/nginx/nginx.conf nginx: неудалось протестировать конфигурационный файл /etc/nginx/nginx.conf

Так много непроверенных предложений на форумах nginx, большинство из них даже не проходят проверку конфигурации.

Один из перспективных вариантов – Ограничение скорости в Nginx по рефереру? — Недостатком этой версии является то, что вся конфигурация повторяется для каждого разного ограничения (у меня много правил переписывания)

Кто-нибудь узнал что-то полезное?

К сожалению, таким образом нельзя динамически задавать параметры, модуль ограничения запросов этого не поддерживает.

Ссылка, которую вы нашли, вероятно, единственный способ достичь этого. Используйте директиву include, чтобы “избежать” повторения вашей конфигурации.

Но что, если сторонний краулер вдруг начнет выдавать себя за пользователя goodbot?

Сегодня я смог реализовать ограничение скорости на основе user agent; попробуйте это:

map $http_user_agent $bad_bot {
    default 0;
    (foo|bar) 1;
}

map $http_user_agent $nice_bot {
    default "";
    (baz|qux) 1;
}

limit_req_zone $nice_bot zone=one:10m rate=1r/s;
limit_req_status 429;

server {
    ...
    location / {
        limit_req zone=one nodelay;
        if ($badbot) {
            return 403;
        }
        ...
    }
}

Очень запоздалый ответ. Но так как я потратил большую часть сегодняшнего дня на изучение этой проблемы, я подумал, что покажу, что сработало для меня. Кратко, это использование map и перезапуск службы вместо простого сигнала о перезагрузке.

Вот что у меня есть ближе к началу моего файла sites-available/default:

# Строки user agent могут быть довольно длинными
map_hash_bucket_size 256;

# Определяем тип агента (бот или нет)
map $http_user_agent $agent_type {

    # Не бот
    default  0;

    # Все ниже перечисленные - это боты, которые должны иметь ограничение скорости
    "~*(Amazonbot|ClaudeBot|DataForSeoBot|GPTBot|SemrushBot)"  1;
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, как Gecko) Chrome/127.0.0 Safari/537.36"  1;
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, как Gecko) Chrome/133.0.0.0 Safari/537.36"  1;
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, как Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.43"  1;

}

# Определяем зоны ограничения скорости для использования позже

map $agent_type $default_zone_key {
    default  '';
    0  $binary_remote_addr;
}
limit_req_zone $default_zone_key zone=default_zone:20m rate=5r/s;

map $agent_type $bot_zone_key {
    default  '';
    1  $binary_remote_addr;
}
limit_req_zone $bot_zone_key zone=bot_zone:10m rate=6r/m;

Обратите внимание, что помимо некоторых ботов, которые объявляют о себе (например, ClaudeBot и GPTBot), я добавил несколько случаев “точно такого же” для некоторых ботнетов, которые не объявляют о себе. Возможно, я случайно наказываю некоторых реальных пользователей. Но я просто рад, что это работает.

Затем в разделе server у меня есть это:

server {
    server_name  somedomain.com;
    ...

    limit_req zone=default_zone burst=50 nodelay;
    limit_req zone=bot_zone burst=10 nodelay;
    limit_req_status 429;  # Слишком много запросов

    ...

    # Хотите узнать, считается ли вы ботом? Раскомментируйте следующее:
    #add_header  X-Routing-Agent-Type "$agent_type";
}

Если вы не понимаете, что происходит, я объясню. Как относительно начинающий в NGINX я вас понимаю. limit_rate_zone позволяет задать ключ. Если он пуст, то это правило фактически игнорируется. В нашем случае мы подаем IP-адрес. Более конкретно, у нас есть два правила. Одно правило совпадает со всеми IP-адресами, связанными с ботами (по user agent). Другое правило совпадает со всеми IP-адресами, которые нет. Эти блоки map $agent_type <ключ> заполняют эти два ключа IP-адресов или пустых строк.

Стоит отметить, что вы можете добавить больше номеров $agent_type, если хотите более тонкое градиентирование, чем просто “бот” и “все остальное”. Вам просто нужно будет добавить больше различных блоков определений и строк.

Сегодня я был так расстроен, потому что многие из того, что я пробовал, не работало. Только под конец я понял, что NGINX не загружает мою конфигурацию, как ожидалось. Я использовал nginx -s reload. Все заработало, когда я вместо этого использовал service nginx restart.

.

Ответ или решение

Вопрос о том, как ограничить скорость запросов в Nginx на основе User-Agent, является актуальной задачей для администраторов серверов, стремящихся оптимизировать нагрузку и защитить свои ресурсы от потенциально вредоносных или нежелательных ботов. Давайте подробно разберем, как реализовать такую конфигурацию и на что стоит обратить внимание.

Теория

Цель состоит в том, чтобы создать три различные стратегии обработки запросов, основанные исключительно на User-Agent:

  1. Браузеры пользователей: Ограничение скорости 1 запрос в секунду (1r/s) для каждого IP-адреса.
  2. Поисковые боты (например, Googlebot и Bingbot): Большее ограничение скорости — 10 запросов в секунду (10r/s).
  3. Плохие боты: Прямой отказ в доступе с кодом ответа HTTP 403.

Для выполнения этих задач используется модуль Nginx для ограничения запросов (limit_req), который требует жесткого контроля конфигурации и тщательной настройки.

Пример

Важно использовать директиву map для классификации User-Agent. Мы создадим несколько map, которые позволят накладывать различные условия на определенные группы пользователей:

http {
    # Регистрация User-Agent
    map $http_user_agent $uatype {
        default 'user';
        ~*(google|bing|msnbot) 'okbot';
        ~*(slurp|nastybot) 'badbot';
    }

    # Определение зон ограничения запросов
    limit_req_zone $binary_remote_addr zone=user_zone:10m rate=1r/s;
    limit_req_zone $binary_remote_addr zone=bot_zone:10m rate=10r/s;

    server {
        ...

        location / {
            # Ограничить доступ для плохих ботов
            if ($uatype = 'badbot') {
                return 403;
            }

            # Применение ограничений для браузеров пользователей
            limit_req zone=user_zone burst=5 nodelay;

            # Применение ограничений для хороших ботов
            if ($uatype = 'okbot') {
                limit_req zone=bot_zone burst=10 nodelay;
            }

            ...
        }

        ...
    }
}

Применение

Теперь мы подробно разберем, как правильно реализовать этот подход, учитывая ограничения конфигурации Nginx.

Шаг 1: Настройка map

map позволяет динамически задавать переменные на основе условий. В нашем случае мы использовали регулярные выражения для определения, является ли User-Agent плохим ботом (badbot), хорошим ботом (okbot) или пользовательским (user). Мы создали три категории, но вы можете добавлять больше в зависимости от необходимости.

Шаг 2: Определение зон ограничения

Директива limit_req_zone используется для установления зон ограничения скорости. Каждая зона основана на IP-адресе пользователя ($binary_remote_addr), что делает ограничения применимыми отдельно для каждого IP.

Шаг 3: Конфигурация сервера

В блоке сервера мы применяем мультиустойчивую логику через map и limit_req. Это позволяет реализовать более сложные стратегии на уровне location.

Решение проблем с if

Использование if в Nginx может быть проблематичным, так как оно не всегда работает предсказуемо. Вместо этого рекомендуется использовать встроенные механизмы Nginx, такие как map и ngx_http_rewrite_module для задания условий.

Кроме того, важно использовать правильный подход к перезапуску и повторному анализу конфигурации Nginx. Часто nginx -s reload может не работать правильно, и требуется более тщательный подход, например, sudo service nginx restart, чтобы убедиться, что изменения применились корректно.

Заключение

Настройка ограничения скорости запросов на основе User-Agent в Nginx — это более сложная задача, чем может показаться на первый взгляд. Она требует детального понимания работы Nginx и возможности применять его богатый функционал для достижения поставленных целей. Важно не только стандартизировать ваш подход к классификации запросов, но и быть готовым к адаптации при возникновении новых сценариев использования или угроз.

Учитывая вышеописанные методы, можно эффективно управлять нагрузкой на ваш сервер, обеспечивая безопасность и высокую производительность для конечных пользователей.

Оцените материал
Добавить комментарий

Капча загружается...