☰
WORDPRESS / PRACTICE

Как ограничить попытки входа в WordPress через Nginx

Как ограничить попытки входа в WordPress через Nginx

Даже сложный пароль не останавливает ботов от массовых попыток входа в WordPress. Автоматизированные сети отправляют сотни и тысячи POST-запросов к /wp-login.php, из-за чего создаётся лишняя нагрузка на PHP-FPM, базу данных и сервер.

Rate limiting на уровне Nginx ограничивает частоту таких запросов ещё до их передачи в PHP. Это не замена MFA, надёжным паролям и контролю учётных записей, но эффективный дополнительный барьер против автоматизированного brute-force.

Как работает ограничение запросов в Nginx

Nginx может вести счётчик запросов для каждого IP-адреса и не пропускать их чаще заданного лимита. Для wp-login.php обычно достаточно разрешить примерно один запрос в секунду, оставив небольшой burst для кратковременных пиков.

Директива limit_req_zone создаёт общую зону хранения счётчиков. Параметр rate=1r/s означает среднюю скорость один запрос в секунду для одного IP-адреса. burst=5 разрешает короткую очередь или всплеск из пяти дополнительных запросов. Параметр nodelay не ставит эти запросы в ожидание, а пропускает их сразу в пределах burst; последующие запросы получат ошибку.

  • 429 Too Many Requests сообщает клиенту о превышении лимита.
  • Счётчик необходимо привязывать к реальному IP-адресу клиента.
  • Ограничение лучше применять именно к wp-login.php, а не ко всем PHP-файлам сайта.

Базовая конфигурация для wp-login.php

Зону limit_req_zone размещают в контексте http, а само ограничение — в location для wp-login.php. Расположение файлов зависит от дистрибутива и структуры конфигурации Nginx, поэтому изменяйте активный серверный блок, который обслуживает ваш домен.

В приведённом примере используется отдельный FastCGI-обработчик для wp-login.php. Путь к сокету PHP-FPM, document root и набор fastcgi-параметров необходимо адаптировать к вашему серверу.

  • Убедитесь, что директива limit_req_zone не вставлена внутрь server или location.
  • Проверьте, какой сокет PHP-FPM действительно используется вашим сайтом.
  • Если у вас уже есть отдельный PHP location, не копируйте его механически: перенесите необходимые параметры в точный location для wp-login.php.
http {
    limit_req_zone $binary_remote_addr zone=wp_login:10m rate=1r/s;

    server {
        server_name example.com;
        root /var/www/example.com/public;

        location = /wp-login.php {
            limit_req zone=wp_login burst=5 nodelay;
            limit_req_status 429;

            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_pass unix:/run/php/php-fpm.sock;
        }
    }
}

Как интегрировать правило с существующим PHP-FPM location

В рабочей конфигурации часто уже есть блок location ~ \.php$, который передаёт PHP-файлы в PHP-FPM. Точный location = /wp-login.php имеет более высокий приоритет для этого пути, поэтому он может перехватить запрос раньше общего PHP-блока.

Поэтому в точном location необходимо оставить все нужные FastCGI-параметры и fastcgi_pass. Если добавить только limit_req, но не передать запрос в PHP-FPM, страница входа перестанет работать.

Самый безопасный подход — взять FastCGI-часть из уже работающего PHP location и добавить к ней ограничение. Не изменяйте одновременно версию PHP, root, правила кеширования и другие параметры без необходимости.

  • Проверьте, содержит ли fastcgi_params параметр SCRIPT_FILENAME в вашей системе; при необходимости задайте его явно.
  • Не указывайте вымышленный путь к сокету: он может называться, например, php8.2-fpm.sock или использовать TCP-подключение.
  • После изменений протестируйте не только главную страницу, но и открытие формы входа, а также сам вход в панель администратора.

Проверка, применение и контроль работы правила

Перед перезагрузкой Nginx проверьте синтаксис конфигурации. Если команда возвращает ошибку, не перезапускайте сервис, пока проблема не будет устранена.

После успешной проверки примените конфигурацию без разрыва активных соединений. Затем проверьте access log и error log: превышение лимитов должно быть заметно по статусу 429 или сообщениям limit_req.

  • Проверка конфигурации: nginx -t
  • Применение изменений: systemctl reload nginx
  • Проверка ответа: curl -I https://example.com/wp-login.php
  • Для POST-запросов выполняйте тестирование осторожно, чтобы не создавать ненужные попытки входа.
sudo nginx -t && sudo systemctl reload nginx

Реальный IP-адрес за reverse proxy или CDN

Если сайт работает за Cloudflare, балансировщиком, reverse proxy или другим промежуточным сервером, Nginx может видеть IP прокси вместо IP посетителя. В таком случае все пользователи попадут под общий лимит, и обычные попытки входа могут начать получать ответ 429.

Сначала настройте модуль realip: укажите доверенные адреса прокси и правильный заголовок, который они передают. Нельзя бездумно доверять произвольному X-Forwarded-For, иначе клиент сможет подменить IP и обойти ограничение.

После настройки проверьте access log: в нём должен отображаться реальный адрес клиента, а не только адрес CDN или балансировщика. Список доверенных сетей должен соответствовать документации вашего прокси и регулярно обновляться.

  • Не используйте заголовок посетителя как источник IP без проверки доверенного прокси.
  • Убедитесь, что $binary_remote_addr вычисляется уже после обработки realip.
  • Проверьте лимиты из разных сетей: домашней, мобильной и через корпоративный прокси.

Типичные ошибки и настройка лимита

Слишком строгий лимит может мешать легитимным пользователям, особенно если несколько человек входят с одного офисного IP-адреса или весь мобильный оператор использует общий NAT. Начните с умеренного значения и наблюдайте за логами.

Ограничение для всех запросов к wp-login.php также распространяется на GET-запрос, который открывает форму входа. Для большинства сайтов это приемлемо, однако нестандартные интеграции или системы автоматизации могут потребовать отдельного тестирования.

Не следует воспринимать rate limiting как полноценную систему защиты. Если учётная запись уже скомпрометирована, Nginx не обнаружит проблему самостоятельно.

  • Ошибка 404 после изменений часто означает неправильный root или неполный FastCGI location.
  • Ошибка 502 обычно указывает на неправильный сокет PHP-FPM или недоступность сервиса PHP-FPM.
  • Массовые ответы 429 для всех пользователей часто вызваны некорректным определением реального IP за reverse proxy.
  • Для дополнительной защиты используйте MFA, уникальные пароли, обновления WordPress и блокировку скомпрометированных учётных записей.

Частые вопросы

Достаточно ли rate limiting для защиты WordPress от brute-force?

Нет. Он снижает скорость автоматизированных попыток и нагрузку на PHP-FPM, но не заменяет MFA, надёжные пароли, обновление ядра и плагинов, а также мониторинг учётных записей.

Почему после настройки все пользователи получают 429?

Чаще всего Nginx видит общий IP-адрес reverse proxy или CDN. Настройте realip для доверенных прокси и проверьте, какой адрес записывается в access log.

Где размещать limit_req_zone?

Директива limit_req_zone должна находиться в контексте http. Директиву limit_req, которая включает зону для конкретного пути, размещают в server или location.

Что делать, если wp-login.php перестал работать после изменений?

Выполните nginx -t, проверьте error log, сокет PHP-FPM, root и FastCGI-параметры. Точный location для wp-login.php должен самостоятельно содержать корректный fastcgi_pass и необходимые параметры.

Вывод

Rate limiting для wp-login.php на уровне Nginx снижает количество автоматизированных попыток входа ещё до запуска WordPress и PHP. Начните с лимита один запрос в секунду и небольшого burst, проверьте реальный IP-адрес клиента и внимательно протестируйте конфигурацию.

После внедрения отслеживайте коды 429 и журналы сервера. Если сайт работает за прокси или CDN, корректное определение реального IP имеет критическое значение, иначе защита может блокировать обычных посетителей вместо ботов.

← Все материалы WordPress