В середине октября 2026 года сообщество следило за публичными графиками Cloudflare Radar по сети Яндекса, AS13238. Метрика, которую Cloudflare публикует для этого ASN, классифицировала 99,6% HTTP-запросов как бот-трафик, а на Hacker News сообщество сообщило о резком падении этого объёма после заявленного удара по дата-центру Яндекса.[12] Какова бы ни была точная причина, сигнал тот же, что вы видите в своих логах доступа: заметная доля «бот-флуда» на публичный сайт приходит с небольшого числа сетей и краулеров и выглядит как запросы с узнаваемыми user-agent.
Управлять этими волнами в источнике вы не можете. Управлять можно только собственным edge. Если nginx работает у вас как reverse proxy перед приложением, у вас есть четыре реальных рычага, и три из них есть в stock-nginx:
- robots.txt для краулеров, которые сотрудничают.
map+return 444для жёсткой блокировки известных AI-краулеров по user-agent.limit_reqдля ограничения флуда, который подделывает или пропускает user-agent.- TLS-фингерпринтинг (JA3/JA4) для краулеров, которые притворяются браузером. Это сложный уровень, и stock-nginx его не умеет (подробности ниже).
Этот гайд предполагает, что у вас уже есть рабочий reverse proxy на nginx; если нет, начните с нашего укреплённого конфига reverse proxy.
Знайте user-agent, которые блокируете
Прежде чем писать хоть одну директиву, поймите: «AI-краулер» это не одна сущность. Каждый вендор запускает несколько ботов с разными задачами, и блокировка не того бота лишит вас видимости в поисковом продукте, который вам, возможно, нужен. Вот токены, которые вы увидите в 2026 году, из документации самих вендоров:
| Токен user-agent | Оператор | Для чего краулит |
|---|---|---|
GPTBot |
OpenAI | Контент для обучения генеративных foundation-моделей.[2] |
OAI-SearchBot |
OpenAI | Показ сайтов в результатах поиска ChatGPT; при отказе вы исчезаете из ответов поиска ChatGPT.[2] |
ChatGPT-User |
OpenAI | Загрузка страниц по запросу пользователя ChatGPT; инициировано пользователем, robots.txt может не применяться.[2] |
ClaudeBot |
Anthropic | Контент для обучения моделей Claude.[3] |
Claude-SearchBot, Claude-User |
Anthropic | Поисковая индексация и пользовательские загрузки; правила отдельные от ClaudeBot.[3] |
Bytespider |
ByteDance | Агрессивный веб-краулер, связанный с продуктами ByteDance.[7] |
Amazonbot |
Amazon | Улучшение продуктов Amazon; может использоваться для обучения AI-моделей Amazon.[4] |
Google-Extended |
Не краулер. Токен robots.txt, управляющий обучением и grounding моделей Gemini, без влияния на Google Search.[5] | |
Meta-ExternalAgent |
Meta | Обучение foundation-моделей AI и прямая индексация контента.[6] |
Две вещи в этой таблице легко понять неправильно.
Google-Extended никогда не появляется в user-agent. Ни один запрос не содержит «Google-Extended» в заголовке User-Agent. Это отдельный product-токен, который вы кладёте в robots.txt: он говорит Google, что контент, скрауленный с вашего сайта, нельзя использовать для обучения будущих моделей Gemini или для grounding в Gemini Apps и Vertex AI, и Google прямо пишет, что это не влияет на включение сайта в Google Search и не является сигналом ранжирования.[5] Поэтому Google-Extended обрабатывается в robots.txt, а не в nginx-мапе.
Пользовательские фетчеры могут не соблюдать robots.txt. OpenAI документирует, что запросы ChatGPT-User инициируются пользователем и правила robots.txt к ним могут не применяться.[2] Amazon говорит то же про Amzn-User.[4] Это важно для уровня enforcement: вежливых контролей недостаточно.
Уровень 1: robots.txt, слой сотрудничества
robots.txt регулируется RFC 9309 (Robots Exclusion Protocol, стандарт IETF с 2022 года). Для этой задачи важны два свойства. Первое: это набор просьб, а не авторизация доступа: стандарт прямо говорит, что эти правила не являются формой контроля доступа, и любой краулер может их игнорировать.[1] Второе: матчинг идёт по product-токену: краулер находит группу, чья строка user-agent совпадает с его токеном, и выигрывает самое длинное совпадение пути, а сам /robots.txt разрешён всегда.[1]
То есть robots.txt это вежливый слой переговоров для послушных краулеров. Конфиг 2026 года, который сохраняет видимость в поиске, но отказывается от обучения AI, выглядит так:
# /var/www/example.com/robots.txt
User-agent: *
Allow: /
# AI-трейнинг и модельные краулеры: блокируем
User-agent: GPTBot
Disallow: /
User-agent: ClaudeBot
Disallow: /
User-agent: Bytespider
Disallow: /
User-agent: Amazonbot
Disallow: /
User-agent: Meta-ExternalAgent
Disallow: /
# Google-Extended это токен, а не краулер: отказ от обучения/grounding в Gemini
User-agent: Google-Extended
Disallow: /
# Поисковые боты, которые вам, возможно, нужны (правьте под себя):
User-agent: OAI-SearchBot
Allow: /
User-agent: Claude-SearchBot
Allow: /
Обратите внимание: решение блокировать OAI-SearchBot это бизнес-решение. OpenAI говорит, что сайты, отказавшиеся от OAI-SearchBot, не появятся в ответах поиска ChatGPT, хотя могут остаться как навигационные ссылки.[2] Хотите, чтобы поиск ChatGPT цитировал вас, оставляйте Allow.
Нестандартная директива, о которой стоит знать: Crawl-delay. Anthropic явно поддерживает её для своих ботов и документирует User-agent: ClaudeBot + Crawl-delay: 1 как способ замедлить краулинг без блокировки.[3] Amazonbot, напротив, директиву crawl-delay вообще не поддерживает.[4] Воспринимайте Crawl-delay как специфику вендора, а не универсальное правило.
Главная оговорка содержится в самом RFC 9309: это просьбы, а не enforcement.[1] Краулеры, которые важнее всего для нагрузки на сервер, это как раз те, что могут не читать или не соблюдать robots.txt. Для этого и нужны nginx-уровни.
Уровень 2: map + return 444, слой enforcement
Модуль ngx_http_map_module создаёт переменную, значение которой зависит от другой переменной, а маппинг задаётся один раз в контексте http.[8] Его regex-синтаксис это ровно то, что нужно для списка блокировки по user-agent: ~ для регистрозависимого матчинга и ~* для регистронезависимого, проверка по порядку, плюс default для всего остального.[8]
Положите это в файл, подключаемый из блока http (обычно /etc/nginx/conf.d/ai-scrapers.conf):
# /etc/nginx/conf.d/ai-scrapers.conf
# Матчим токен, а не полную строку UA: версии меняются.
map $http_user_agent $is_ai_scraper {
default 0;
~*GPTBot 1;
~*OAI-SearchBot 1; # уберите, если хотите, чтобы поиск ChatGPT цитировал вас
~*ClaudeBot 1;
~*Claude-SearchBot 1;
~*Bytespider 1;
~*Amazonbot 1;
~*Meta-ExternalAgent 1;
~*meta-externalagent 1;
}
Затем в server-блоке вашего сайта блокируем совпадения. Самый чистый ход в stock-nginx это return 444, нестандартный код nginx, который закрывает соединение вообще без отправки заголовков ответа.[9] Краулеру это стоит полного TCP-раундтрипа, и парсить нечего:
# в server { }
if ($is_ai_scraper) {
return 444;
}
Две практические заметки про этот уровень.
Матчите токен, а не полную строку. Пример строки GPTBot от OpenAI заканчивается compatible; GPTBot/1.4; +https://openai.com/gptbot, и номер версии меняется.[2] Подстрока-регэксп ~*GPTBot ловит её независимо от версии. То же для Amazonbot/0.1 и meta-externalagent/1.1.[4][6] Если краулер крутит регистр UA, ~* (регистронезависимый) справится; хотите строгости, используйте ~.
Для флуда предпочитайте 444, а не 403, но логируйте решение. return 403 возвращает настоящий HTTP-ответ, то есть соединение завершается и запрос виден в access-логе как 4xx. return 444 молча рвёт соединение. Для защиты 444 дешевле; для отладки и честной аналитики, возможно, захотите 403, чтобы блоки было можно посчитать. Разумный компромисс: оставить 444 для известных трейнинг-краулеров и считать их в отдельном access-логе либо просто грепать по $http_user_agent.
Проверьте curl’ом до того, как перезагружать в прод:
curl -sS -o /dev/null -w '%{http_code}\n' -A 'Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; GPTBot/1.4; +https://openai.com/gptbot' https://example.com/
# 000 -> соединение закрыто без ответа (444 сработал)
curl -sS -o /dev/null -w '%{http_code}\n' https://example.com/
# 200 -> обычные браузеры не затронуты
Уровень 3: limit_req, демпфер флуда
Блокировка по user-agent убирает краулеров, которые представляются. Остаётся флуд тех, кто подделывает настоящий браузерный UA или не шлёт UA вовсе. Для этого правильный инструмент это ngx_http_limit_req_module, который реализует rate limit по модели leaky bucket, ключуемый любой переменной, обычно клиентским IP.[10]
Зона объявляется в контексте http, а ссылаются на неё в server или location:
# /etc/nginx/conf.d/bot-flood.conf (контекст http)
limit_req_zone $binary_remote_addr zone=perip:10m rate=5r/s;
# server { ... location / { ... } }
server {
listen 443 ssl;
server_name example.com;
location / {
# proxy_pass / корневой конфиг из вашего reverse-proxy...
limit_req zone=perip burst=20 nodelay;
}
}
Несколько фактов из документации модуля, которые определяют настройку:
- Зона использует модель leaky bucket: запросы обрабатываются со скоростью
rate, избыток задерживается доburst, а сверх этого запрос отклоняется.[10] nodelayубирает очередь: лишние запросы отклоняются сразу, а не задерживаются. Используйте для бот-трафика, где задержанный ответ бессмыслен; опускайте там, где лучше притормозить, чем отрезать.[10]- Параметр
delay(nginx 1.15.7+) задерживает до лимита и отклоняет сверх него, что даёт хорошую защиту API от всплесков без очереди флуда.[10] limit_req_statusпо умолчанию равен503; можно поставить429 Too Many Requests, если это лучше ложится на контракт с клиентами.[10]- Переменная
$limit_req_status(1.17.6+) сообщаетPASSED,DELAYEDилиREJECTEDпо каждому запросу, так что можно логировать и считать, что реально сделал лимитер.[10] - Арифметика размера зоны: один мегабайт зоны держит примерно 16 тысяч 64-байтных состояний на 32-битных платформах или 8 тысяч 128-байтных на 64-битных, и состояние создаётся на каждый отдельный ключ (здесь, на клиентский IP).[10] Зоны 10m хватает небольшому VPS с запасом; размерьте под число ожидаемых уникальных IP, а не под частоту запросов.
Универсально правильной ставки не существует, и мы не будем её выдумывать. Честный процесс: посмотрите реальные access-логи, найдите пиковую частоту вашего нормального трафика (люди, ваш мониторинг) и поставьте лимит на порядок выше, чтобы отрезался флуд, а не пользователи. Для безопасного ввода в эксплуатацию есть limit_req_dry_run on (1.17.1+): он считает лишние запросы в зоне без применения, и это правильный способ проверить новый лимит на живом трафике до того, как он начнёт отклонять.[10]
Две оговорки про IP-лимиты. Первая: IPv6 меняет картину: $binary_remote_addr занимает 16 байт для IPv6, и /64 за NAT или большой прокси-пул могут выглядеть как один адрес, так что per-IP лимит способен отсечь легитимных пользователей на общих адресах. Вторая: распределённый флуд с многих IP обходит per-IP лимитер полностью; в этой точке лимит это последний рубеж для вашего origin, а не лекарство.
Уровень 4: TLS-фингерпринты (JA3/JA4), и почему это сложно
Краулер, который обходит уровни 2 и 3, это тот, кто шлёт настоящий Chrome-юзер-агент с многих IP. Обычный способ ловить таких это TLS-фингерпринт клиента: JA3 (MD5-хеш полей TLS ClientHello) или его преемник JA4, который нормализует тот же сигнал в читаемую строку. Разные HTTP-клиенты отдают наблюдаемо разные формы ClientHello, поэтому настоящий Chrome на Windows и Python-HTTP-клиент AI-скрейпера дают разные фингерпринты даже с одинаковыми user-agent.
Вот честная часть: в stock-nginx нет поддержки JA3/JA4. Это не директива из документации nginx, и в дистрибутивном пакете вы её не найдёте. Реализация означает сборку nginx из исходников с модулем третьей стороны и пропатченным OpenSSL, который отдаёт сырой ClientHello. Проекты вроде nginx-ssl-fingerprint делают ровно это: патчат ядро nginx и OpenSSL и выставляют переменные вроде $http_ssl_ja3 и $http_ssl_ja4, которые затем можно использовать в map точно так же, как user-agent.[13] Работает и является реальной возможностью, но это обязательство на сборку из исходников: вы берёте на себя поддержку пропатченных nginx и OpenSSL. Для большинства небольших VPS такая цена обслуживания не оправдана, а UA-мап плюс rate limiting и так убирают подавляющую часть AI-скрейперского трафика.
Реалистичная альтернатива, когда нужна защита на уровне фингерпринта без сборки, это поставить перед nginx управляемый edge, который делает фингерпринтинг за вас. Это другой деплой, а не то, что nginx делает сам по себе.
Не сломайте поисковики
Весь смысл матчинга токена, а не блокировки всего подряд, в том, что настоящие поисковые краулеры представляются так же, и вы хотите, чтобы они продолжали приходить. Краулеры Google идентифицируются тремя способами: user-agent, исходный IP и reverse-DNS-хостнейм, и Google публикует и IP-диапазоны, и процедуру проверки, чтобы отличить настоящего Googlebot от подделки.[14] Если собираетесь агрессивно раздавать return 444, вынесите Googlebot, Bingbot и YandexBot в явный allowlist и проверьте выборку их запросов по reverse DNS, прежде чем доверять лог-строке, которая называет себя одним из них.
Блокировка Googlebot общим правилом это то, как сайт тихо исчезает из Google Search. Именно поэтому Google вынесла Google-Extended отдельно: можно оставить Googlebot краулить и индексировать, при этом отказавшись от обучения Gemini, целиком через robots.txt и без всякого участия nginx.[5]
Проверьте, затем перезагрузите
Внесите изменения обычным способом и валидируйте каждый уровень независимо:
sudo nginx -t # конфиг сначала должен чисто парситься
sudo systemctl reload nginx
# проверки против живого сервера
curl -sS -o /dev/null -w '%{http_code}\n' -A 'GPTBot/1.4' https://example.com/
curl -sS -o /dev/null -w '%{http_code}\n' -A 'Bytespider' https://example.com/
curl -sS -o /dev/null -w '%{http_code}\n' https://example.com/ # люди по-прежнему 200
# смотрим, что сделал лимитер
grep ' 503 ' /var/log/nginx/access.log | tail
Если перезагрузки автоматизированы, гайд по Control API показывает, как превратить перезагрузку в запрос, отвечающий JSON-вердиктом вместо строки в логе.
Короткая версия
Три уровня stock-nginx закрывают практический случай 2026 года: robots.txt по RFC 9309 для сотрудничающих краулеров (блокируем GPTBot, ClaudeBot, Bytespider, Amazonbot, Meta-ExternalAgent и токен Google-Extended; оставляем OAI-SearchBot, если хотите, чтобы ChatGPT вас цитировал); map по $http_user_agent с ~*-регэкспами токенов и return 444 для краулеров, которые представляются; и зона limit_req по ключу $binary_remote_addr с nodelay для флуда, который подделывает или пропускает user-agent. Сначала валидируйте через limit_req_dry_run, и никогда не бейте Googlebot, Bingbot и YandexBot той же кистью. Фингерпринтинг JA3/JA4 реален, но требует nginx из исходников с модулем третьей стороны, так что относитесь к нему как к пути эскалации, а не как к умолчанию. Дефолты выше это те, что реально ставятся на stock-сервер.
Источники
- RFC 9309 - Robots Exclusion Protocol (группы, product-токены, longest-match; «не форма авторизации доступа»; /robots.txt разрешён всегда). https://www.rfc-editor.org/rfc/rfc9309.html - проверено 2026-10-13
- OpenAI - Overview of OpenAI Crawlers (GPTBot, OAI-SearchBot, ChatGPT-User; теги robots.txt; опубликованные IP; обновление ~24ч). https://developers.openai.com/api/docs/bots - проверено 2026-10-13
- Anthropic - Does Anthropic crawl data from the web… (ClaudeBot, Claude-SearchBot, Claude-User; поддержка Crawl-delay; соблюдение robots.txt). https://support.anthropic.com/en/articles/8896518-does-anthropic-crawl-data-from-the-web-how-can-site-owners-block-the-crawler - проверено 2026-10-13
- Amazon - About AmazonBot (Amazonbot/0.1; соблюдает Robots Exclusion Protocol; не поддерживает crawl-delay; robots-мета-теги; опубликованные IP). https://developer.amazon.com/amazonbot - проверено 2026-10-13
- Google - Google’s common crawlers (Google-Extended это отдельный product-токен для обучения/grounding в Gemini; без влияния на Google Search). https://developers.google.com/crawling/docs/crawlers-fetchers/google-common-crawlers - проверено 2026-10-13
- Meta - Meta Web Crawlers (Meta-ExternalAgent обучает foundation-модели AI / индексирует контент). https://developers.facebook.com/docs/sharing/webmasters/crawler - проверено 2026-10-13
- monperrus/crawler-user-agents - поддерживаемый список user-agent краулеров (Bytespider, GPTBot, Amazonbot, meta-externalagent, OAI-SearchBot, Claude-SearchBot). https://github.com/monperrus/crawler-user-agents - проверено 2026-10-13
- nginx - Module ngx_http_map_module (
map-переменные, регэкспы~/~*,default). https://nginx.org/en/docs/http/ngx_http_map_module.html - проверено 2026-10-13 - nginx - Module ngx_http_rewrite_module (
return 444закрывает соединение без ответа). https://nginx.org/en/docs/http/ngx_http_rewrite_module.html - проверено 2026-10-13 - nginx - Module ngx_http_limit_req_module (leaky bucket, burst, nodelay, delay 1.15.7+, dry_run 1.17.1+, limit_req_status по умолчанию 503, $limit_req_status 1.17.6+, арифметика размера зоны). https://nginx.org/en/docs/http/ngx_http_limit_req_module.html - проверено 2026-10-13
- nginx - download (mainline 1.31.8, 2026-10-21; stable 1.30.6, 2026-10-14). https://nginx.org/en/download.html - проверено 2026-11-07
- Cloudflare Radar - Bot traffic from AS13238 (Yandex), последние 7 дней (классификация: 99,6% бот); тред Hacker News «Sudden drop in Cloudflare bot traffic after strike on Yandex datacenter» (сообщество сообщает, 2026-10-11). https://radar.cloudflare.com/bots/as13238 ; https://news.ycombinator.com/item?id=50041619 - проверено 2026-10-13
- nginx-ssl-fingerprint - модуль JA3/JA4 для nginx (требует патчей ядра nginx и OpenSSL, сборка из исходников; отдаёт $http_ssl_ja3/$http_ssl_ja4). https://github.com/phuslu/nginx-ssl-fingerprint - проверено 2026-10-13
- Google - Overview of Google crawlers and fetchers (идентификация по user-agent, исходному IP и reverse DNS). https://developers.google.com/crawling/docs/crawlers-fetchers/overview-google-crawlers - проверено 2026-10-13