Отчёт о проделанной работе · glavdezcentr.ru

Защита сайта от паразитной нагрузки ботов

Сайт был перегружен автоматическими запросами: сервер работал на пределе, страницы отдавались медленно. Мы отделили ботов от посетителей, перевели обработку лишних запросов на быстрый веб-сервер и устранили причины, по которым боты находили «бесконечные» адреса. Нагрузка на движок сайта снизилась в 5 раз, а на сервер — в 20 с лишним раз. Посетители из поиска не пострадали.

Период работ: 14–19 октября 2026
Контрольный замер: 20–21 октября 2026
Сравнение с: 4–13 октября 2026

01Итоги в цифрах

Типичные сутки до начала работ (в среднем за 4–13 октября) против 20 октября, первых полных суток после всех изменений.

Запросов к движку сайта в сутки
54 тыс.
было ≈ 286 тыс. · −81%
Нагрузка на сервер (load average, 4 ядра)
0,2–0,8
было 16–17
Трафик страниц в сутки
4 ГБ
было ≈ 21 ГБ · −81%
Записей в журнале ошибок в сутки
793
было ≈ 38 тыс. · −98%

Посещаемость из поисковых систем не изменилась: около 1 000 уникальных посетителей и 2,3 тыс. переходов в сутки, как и до работ. Защита отсекает ботов, а не людей.

02Что было

Проблему нашли 14 октября: сервер с 4 ядрами работал при нагрузке 16–17, то есть очередь задач в четыре раза превышала его возможности. Анализ журналов показал, откуда она берётся.

ИсточникЧто происходилоЗапросов в сутки
Ботнет из ~26 тыс. адресовБез реферера, с поддельными браузерами Chrome. Обходил ссылки вида /catalog/cart/<хэш>/: каждый просмотр корзины порождал новый уникальный адрес, и обход никогда не заканчивался100–265 тыс.
Мусорные адресаБоты переходили по ссылкам tel: и mailto: как по страницам, и каждая такая «страница» запускала движок сайта5–40 тыс.
SEO- и ИИ-краулерыSemrush, Ahrefs, Baidu, Bytespider, GPTBot и др. обходили весь сайт без ограниченийдесятки тыс.
FacebookСборщик превью обходил главные страницы всех региональных поддоменов≈ 20 тыс.
Служебные запросыКаждая страница отдельно запрашивала языковой словарь и город по IP: в сутки это почти 90 тыс. дополнительных обращений к движку≈ 85 тыс.

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

03Как устроена защита

Перед сайтом стоит веб-сервер nginx. Он отвечает на запрос за доли миллисекунды и почти не тратит ресурсы. Движок сайта (PHP и база данных) на каждый запрос тратит в сотни раз больше. Главная идея — чтобы ботам отвечал nginx, а до движка доходили только нужные запросы.

До Посетители + боты≈ 450 тыс. запросов/сутки nginxпропускает всё Движок сайта≈ 286 тыс./сутки · перегрузка После Посетители + боты≈ 310 тыс. запросов/сутки nginx: фильтрправила для ботов Движок сайта≈ 54 тыс./сутки Ответ сразу≈ 106 тыс./сутки До Посетители + боты ≈ 450 тыс. запросов/сутки nginx пропускает всё Движок сайта ≈ 286 тыс./сутки · перегрузка После Посетители + боты ≈ 310 тыс. запросов/сутки nginx: фильтр правила для ботов Движок сайта ≈ 54 тыс./сутки · запас ≈ 106 тыс./сутки — ответ сразу, без движка

Отказ — 403

SEO-краулеры, которые не приносят посетителей: Semrush, Ahrefs, DotBot, Baidu, Exa и др.

Ограничение — 429

ИИ-боты и Facebook могут работать, но не чаще заданного темпа. Лишние запросы получают «повторите позже».

Статический ответ

Пустая корзина без товаров отдаётся готовой страницей в 418 байт вместо страницы в 87 КБ, собранной движком.

Редирект и 404

Старые адреса корзины с хэшем ведут на единый адрес, а мусорные tel:/mailto: получают 404.

04Что сделано

Работы шли в три этапа. После каждого этапа мы проверяли журналы и по ним выбирали следующий шаг.

  1. 14 октябряэтап 1
    • Выключен режим отладки на рабочем сервере.
    • Добавлены правила для ботов в nginx: SEO-краулерам отказ, ИИ-ботам и Facebook ограничение частоты.
  2. 15 октябряэтап 2
    • Корзина получила постоянный адрес /catalog/cart/ вместо уникального на каждый просмотр. Старые адреса перенаправляются. #155
    • Удалён отладочный адрес выгрузки базы и кода. #154
    • Меню строится без отдельного запроса к базе на каждый пункт. #153
    • Языковой словарь загружается один раз и кэшируется в браузере. #156
    • Город по IP определяется фоновым запросом, а не при сборке каждой страницы. #157
    • Страницы стали легче: иконка Rutube уменьшена с 205 до 5 КБ, удалён неиспользуемый скрипт. #158
    • Пересжаты изображения статей, новостей и баннеров: 167 → 75 МБ без видимой потери качества.
    • Мусорные адреса tel: и mailto: отсекаются на уровне nginx.
  3. 19 октябряэтап 3
    • Ботнет переключился на сам адрес /catalog/cart/ (60–100 тыс. запросов в сутки). Теперь посетителю без товаров в корзине nginx отдаёт готовую страницу «Корзина пуста», и движок не запускается.
    • Baidu и ExaSearchBot полностью запрещены. Для Facebook введён отдельный лимит — 6 запросов в минуту.
    • Включён журнал запросов, отклонённых nginx, чтобы видеть объём отсечённого трафика.
    • Исправлены предупреждения в модуле региональных редиректов: они давали около 36 тыс. строк в сутки в журнале ошибок. #159

Номера с решёткой — заявки на изменение (pull request) в репозитории сайта. Перед каждым изменением на сервере сохранялась резервная копия.

05Результаты

Данные из журналов сервера, по суткам, с 4 по 20 октября. Вертикальные линии — даты трёх этапов работ. Наведите курсор на столбец, чтобы увидеть значение.

Запросы, дошедшие до движка сайта

тыс. запросов в сутки, без картинок, стилей и скриптов

Пики 11–12 и 15 октября — волны ботнета по адресам корзины. После этапа 2 (15 октября) ботнет переключился на постоянный адрес корзины, поэтому 16–18 октября нагрузка оставалась высокой. Этап 3 закрыл и этот путь: 20 октября до движка дошло 54 тыс. запросов против обычных 250–300 тыс.

Записи в журнале ошибок

тыс. строк в сутки

Посетители из поисковых систем

уникальные IP с переходом из Яндекса, Google и др.

Журнал ошибок почти пуст: 793 строки против обычных 20–30 тыс. Это ускоряет работу и облегчает поиск настоящих неполадок. Всплеск 15–16 октября вызвали предупреждения модуля региональных редиректов, они исправлены 19 октября. Число посетителей из поиска при этом стабильно на протяжении всего периода.

Что nginx отсёк сам, 20 октября

106 тыс. запросов в сутки, движок сайта на них не запускался

Ботнет продолжает приходить: около 82 тыс. запросов в сутки к адресам корзины. Теперь это для сайта почти бесплатно — nginx отвечает на них сразу. Для сравнения: до работ каждый такой запрос собирал страницу в 87 КБ и нагружал базу данных.

Сравнение по суткам

ПоказательДо работ
4–13 окт., среднее
После этапа 2
16–18 окт.
После этапа 3
20 окт.
Изменение
Запросы к движку сайта≈ 286 тыс.≈ 338 тыс.54 тыс.−81%
Трафик страниц (без статики)≈ 21 ГБ≈ 20 ГБ4 ГБ−81%
Служебные POST-запросы≈ 84 тыс.≈ 136 тыс.15 тыс.−82%
Запросы ботнета, дошедшие до движка≈ 32 тыс.≈ 18 тыс.838−97%
Строки в журнале ошибок≈ 38 тыс.≈ 73 тыс.793−98%
Нагрузка на сервер (load average)16–171–20,2–0,8в 20+ раз
Посетители из поиска (уникальные IP)≈ 1 050≈ 8301 043без изменений

Средние «до работ» включают волну ботнета 11–12 октября. Данные за 21 октября (неполные сутки, до 11:40) идут в том же темпе, что и за 20-е.

06Что дальше

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

НаблюдениеРекомендация
Ботнет продолжает обращаться к адресам корзины (≈ 82 тыс./сутки)Ничего не делать: nginx отвечает за доли миллисекунды. Следить по журналу отклонённых запросов.
Несколько источников с подозрительными подписями — Chrome/99 (5,3 тыс./сутки), GuzzleHttp (2,9 тыс.), Chrome/48 (1,8 тыс.)Уточнить, нет ли среди них собственных интеграций (Guzzle — PHP-клиент, часто используется сервисами). Если нет, можно ограничить.
Около 750 предупреждений в сутки от модуля RoistatНе влияют на работу сайта. Модуль не трогаем до решения по договору с Roistat.
Устаревшая платформа сервера (CentOS 7, PHP 5.6)Сейчас ресурсов хватает с запасом. При следующем росте нагрузки в первую очередь стоит обновить платформу.