Нельзя остановить вредоносных ботов. Давайте просто отсекаем их на уровне nginx – как убрать подозрительные URL в конфиге blackhole.conf

Очистка подозрительных URL через nginx blackhole.conf



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

  • Не существующий /wp-admin/
  • /index.php, /xmlrpc.php – даже если PHP не используется
  • .git, .env, /cgi-bin/ – чувствительные файлы и каталоги
  • wso.php, shell.php, test.php

Это не ваш собственный сервис, а мировые сканеры и боты, которые пытаются найти уязвимости. Честно говоря, сервер, который не сталкивается с этим, почти не существует.

Если защита реализована на уровне приложения, большинство запросов обрабатывается как 400/404. Но проблема появляется после этого:

  • Логи загрязняются – до того, как реальные пользователи сделают запрос, половина лога уже заполнена подозрительными запросами.
  • Небольшая нагрузка на CPU – даже «безопасные» запросы требуют лишних вычислений.
  • Усталость админа – каждый раз, открывая логи, видишь сотни строк /wp-login.php.

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

В этой статье:

  • Почему «первичная блокировка на уровне nginx» полезна
  • Как управлять общими правилами через файл blackhole.conf
  • Примеры реальных конфигураций nginx

1. Почему блокировка только в приложении недостаточна

Обычный подход:

  • URL, которого нет в роутере/контроллере → 404
  • Исключения → 400/500
  • Логи → APM / лог‑коллектор

Функционально всё ок, но с точки зрения эксплуатации есть проблемы:

  1. Шум в логах – процент ошибок/404 растёт из‑за сканеров, а не реальных пользователей.
  2. Блокировка слишком глубоко – запрос уже прошёл через фреймворк, мидлвари и роутинг.
  3. Накопительная нагрузка – сканеры приходят постоянно, и их количество может быть значительным.

Поэтому я стараюсь отсеивать «неполезные» запросы как можно выше, в nginx.


2. Создание «черной дыры» в nginx: мгновенное отключение через 444



В nginx есть собственный статус‑код, которого нет в HTTP‑стандарте:

return 444;
  • Не отправляется заголовок, не отправляется тело
  • Просто закрывается TCP‑соединение

С его помощью можно полностью отключить запросы, которые выглядят 100 % подозрительными.

Преимущества:

  • Запрос не доходит до приложения (CPU‑нагрузка нулевая)
  • Логи можно полностью отключить для таких запросов
  • Логи приложения остаются чистыми

3. Управление правилами через один файл blackhole.conf

Вместо того чтобы прописывать правила в каждом сервер‑блоке, удобно хранить их в одном файле, например /etc/nginx/blackhole.conf:

# /etc/nginx/blackhole.conf

# 1. Скрытые и конфиденциальные каталоги (.git, .env, IDE и т.д.)
location ~* (^|/)\.(git|hg|svn|bzr|DS_Store|idea|vscode)(/|$)   { return 444; }
location ~* (^|/)\.env(\.|$)                                    { return 444; }
location ~* (^|/)\.(?:bash_history|ssh|aws|npm|yarn)(/|$)       { return 444; }

# 2. Неиспользуемые CMS‑админки / уязвимости
location ^~ /administrator/                                    { return 444; }
location ^~ /phpmyadmin/                                      { return 444; }

# 3. PHP/CGI/WordPress‑следы
# Рекомендуется для стеков без PHP (Node, Go, Python)
location ~* \.(?:php\d*|phtml|phps|phar)(/|$)                  { return 444; }
location ^~ /cgi-bin/                                         { return 444; }
location ~* ^/(wp-admin|wp-includes|wp-content)(/|$)          { return 444; }

# 4. Часто сканируемые файлы/пути
location ~* ^/(?:info|phpinfo|test|wso|shell|gecko|moon|root|manager|system_log)\.php(?:/|$)? {
    return 444;
}
location ~* ^/(?:autoload_classmap|composer\.(?:json|lock)|package\.json|yarn\.lock|vendor)(?:/|$) {
    return 444;
}
location ~* ^/(?:_profiler|xmrlpc|xmlrpc|phpversion)\.php(?:/|$)? {
    return 444;
}

# 5. Бэкапы/временные/дампы
location ~* \.(?:bak|backup|old|orig|save|swp|swo|tmp|sql(?:\.gz)?|tgz|zip|rar)$ {
    return 444;
}

# 6. well‑known: разрешаем только ACME, остальные закрываем
location ^~ /.well-known/acme-challenge/ {
    root /var/www/letsencrypt;
}
location ^~ /.well-known/ {
    return 444;
}

# 7. Защита методов (опционально)
if ($request_method !~ ^(GET|HEAD|POST|PUT|PATCH|DELETE|OPTIONS)$) {
    return 405;
}

В каждом сервер‑блоке добавляем только одну строку:

http {
    server {
        listen 80;
        server_name example.com;

        include /etc/nginx/blackhole.conf;

        # остальные правила маршрутизации...
    }
}

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


4. Уменьшение шума в логах (опционально)

Если хотите, чтобы запросы, попадающие в черную дыру, вообще не записывались в access_log, можно использовать map:

http {
    map $request_uri $drop_noise_log {
        default                            0;
        ~*^/(?:\.git|\.env)                1;
        ~*^/(wp-admin|wp-includes|cgi-bin) 1;
        ~*\.php(?:/|$)                     1;
    }

    server {
        listen 80;
        server_name example.com;

        include /etc/nginx/blackhole.conf;

        access_log /var/log/nginx/access.log combined if=$drop_noise_log;
    }
}
  • $drop_noise_log = 1 – запрос не логируется
  • $drop_noise_log = 0 – обычный лог

В продакшене сначала включайте логирование, проверяйте, что «правильные» пользователи не попадают в список, а затем переключайте на if=$drop_noise_log.


5. Как избежать ложных срабатываний

Главное правило: не быть слишком агрессивным.

  1. Подбирайте правила под стек – если проект не использует PHP, блокируйте .php полностью. Если у вас Laravel, исключите эти правила.
  2. Начинайте с 404/403 – сначала возвращайте 403, наблюдайте, не мешают ли они реальным пользователям, а потом переходите к 444.
  3. Блокируйте критичные пути.git, .env, бэкапы, phpinfo.php можно закрыть без опасений.
  4. Понимайте приоритеты – в nginx location имеет порядок: точное совпадение, префикс, регулярное выражение. Не ставьте правила выше, чем основной роутер.

6. Где каждая часть отвечает за безопасность

  • nginx blackhole – отсекает «пустые» запросы на раннем этапе.
  • Приложение – проверяет бизнес‑логику, права доступа, валидность входных данных.
  • WAF/другие решения – паттерн‑базированные атаки, DDoS, продвинутый бот‑фильтр.

Каждый слой дополняет остальные, а не заменяет.


Итоги

Если ваш сервис доступен в интернете, полностью избавиться от «подозрительных» запросов невозможно. Но можно изменить подход:

«Если они придут, просто отсекаем их в nginx, не давая дойти до приложения».

С помощью blackhole.conf и ответа 444 вы:

  • Чистите логи приложения
  • Уменьшаете нагрузку на сервер
  • Делаете мониторинг и анализ более удобными

В итоге, когда вы открываете логи в 2 : 00, вместо бесконечной строки /wp-login.php вы видите только реальные запросы – это уже приятный бонус.

Если у вас уже есть nginx, попробуйте добавить свой blackhole.conf. Через несколько дней вы поймёте, почему это было необходимо.

image of nginx block malicious url