Назад в блог
27 октября 2025 г.Sergei Solod5 мин чтения

Мой статический сайт на Next.js получает тысячи сканов уязвимостей в день. Nginx почти не замечает

Логи забиты пробами WordPress, PHP-бэкдоров, .env и .git/config. На моём статическом Next.js + Nginx сайте они в основном превращаются в дешёвые промахи и 404, а нагрузка CPU оставалась прежней. Ниже — что это действительно говорит о безопасности статики, а что нет.

БезопасностьNext.jsNginxDevOpsСтатический хостингПоверхность атаки

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

  • /wp-admin/wp.php
  • /111.php
  • /code.php
  • /.git/config
  • /i.php
  • /admin
  • /api/.env
  • /kal.php

Удивило меня не их количество, а реакция сервера. Пока я наблюдал за этим трафиком, загрузка CPU заметно не менялась.

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

Это пробы, а не доказательство взлома

Легко увидеть /wp-admin/wp.php или /111.php и назвать каждый такой запрос «эксплойтом». Технически это неточно. В основном я вижу автоматический probing: боты перебирают распространённые имена файлов и endpoint'ы и смотрят, что ответит сервер.

Часть путей явно нацелена на WordPress или PHP. Другие, например /.git/config и /api/.env, проверяют, не опубликованы ли случайно конфигурация или секреты. /admin ещё более общий путь и на некоторых сайтах вообще является штатным. Подозрительный запрос показывает, что ищет сканер, но сам по себе не доказывает наличие уязвимости.

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

Почему на моём стеке этот трафик стоит дёшево

На тех страницах, о которых идёт речь, за каждым запросом не стоят PHP runtime и база данных. Nginx раздаёт уже существующие файлы. Если сканер запрашивает /111.php, а такого файла нет, никакое PHP-приложение не запускается, WordPress-код не исполняется и запрос к базе не появляется. Получается обычный промах и 404.

Из-за этого меняется стоимость запроса. В динамическом приложении он может пройти через роутинг, framework runtime, проверку авторизации, рендеринг, базу данных или внешние сервисы. На моём статическом пути движущихся частей намного меньше. Сервер всё равно принимает соединение, разбирает HTTP, ищет ресурс, пишет лог и отправляет ответ, но прикладной работы мало.

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

Важная поправка: статический сайт не «безопасен по определению»

Именно эту часть я сейчас формулировал бы иначе. Статическая архитектура убирает из публичного request path много серверных компонентов, но не отменяет безопасность.

  • Открытый файл остаётся открытым. Если .git, .env, backup или другой секрет случайно окажется в публичной директории, Nginx может так же эффективно отдать его клиенту, если конфигурация это не блокирует.
  • Nginx, TLS, операционная система и сеть никуда не исчезают. Их всё равно нужно нормально настраивать и обновлять.
  • Клиентский код тоже может быть уязвим. Статический HTML не делает JavaScript, браузерную логику авторизации или сторонние скрипты автоматически безопасными.
  • Истощение ресурсов возможно и у статики. Соединения, пропускная способность, TLS handshakes, worker'ы, запись логов и диск конечны. Достаточно большой поток способен навредить и статическому сайту.

Поэтому корректный вывод не «эти запросы вообще не имеют значения», а такой: многим прикладным пробам на этой архитектуре просто нечего исполнять.

«Тысячи сканов в день» могут звучать страшнее, чем являются

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

CPU тоже только один показатель. В моём случае он оставался на том же уровне, и это полезное наблюдение: в тот момент сканеры не создавали заметной вычислительной нагрузки. Но это не доказывает отсутствие других затрат. Для полноценной оценки я бы смотрел ещё на RPS, трафик, активные соединения, загрузку worker'ов Nginx, задержки ответов, объём логов и расход диска.

Что я вынес из этих логов

Главный вывод для меня в том, что архитектура способна сделать целые классы автоматических атак нерелевантными без отдельного правила под каждую сигнатуру сканера. Бот может весь день искать WordPress и PHP-бэкдоры; если в публичном пути нет ни WordPress, ни PHP, именно этим пробам почти не за что зацепиться.

Но я больше не смешиваю «нерелевантно для моего стека» и «безвредный трафик». Мой текущий чек-лист проще:

  • Понимать, какие runtime и сервисы реально доступны из публичного request path.
  • Держать секреты, metadata репозитория, backup'ы и служебные артефакты вне web root либо явно блокировать их.
  • Считать повторяющиеся 404-пробы обычным интернет-шумом, пока нет других признаков целевой атаки или влияния на систему.
  • Не делать вывод «нагрузки нет» только по CPU.
  • Обновлять Nginx, ОС, TLS-библиотеки и зависимости даже у полностью статического приложения.

Чего этот опыт не доказывает

Я не проводил контролируемый benchmark и не имитировал DDoS. Я только наблюдал production-логи и состояние сервера, пока каждый день приходили тысячи сканирующих запросов. Этого достаточно для практического вывода о моей конфигурации, но недостаточно для универсального тезиса «статика всегда побеждает».

Что я могу подтвердить точнее: в моём Next.js static export, который отдаёт Nginx, увиденный мной scanner traffic в основном сводился к дешёвым промахам по файлам и 404, а не доходил до PHP runtime или приложения с базой данных. Пока я это наблюдал, загрузка CPU не менялась.

Вот это преимущество устойчивости для меня действительно важно. Меньше движущихся частей не делает систему неуязвимой. Это просто оставляет случайному интернет-шуму меньше мест, где он может превратиться в настоящую прикладную работу.