Защита WordPress и сервера от взлома: Fail2ban, Nginx и Cloudflare

Вы настроили Nginx reverse proxy, оптимизировали PHP-FPM и ускорили сайт до 90+ баллов в PageSpeed. Но быстрый сайт — это лакомая цель для ботов. Ежедневно тысячи сканеров пытаются подобрать пароль к wp-login.php, эксплуатируют уязвимости плагинов и отправляют DDoS-запросы.

В этом руководстве мы выстроим многоуровневую защиту: от настройки SSH и Fail2ban на уровне сервера до ограничения запросов в Nginx и подключения Cloudflare. Эти меры отсекнут 99% автоматических атак без потери производительности.

Уровень 1: Базовая защита сервера (SSH)

Прежде чем защищать WordPress, нужно закрыть сам сервер. Если злоумышленник получит доступ по SSH, никакие плагины безопасности не помогут.

1. Отключите вход по паролю и используйте SSH-ключи

# Генерация ключа на локальной машине (если нет)
ssh-keygen -t ed25519 -C "admin@custom-code.ru"

# Копирование ключа на сервер
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@your_server_ip

2. Запретите вход для root и измените порт (опционально)

Откройте /etc/ssh/sshd_config и измените параметры:

PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
# Port 2222 # Раскомментируйте, если хотите сменить стандартный порт
sudo systemctl restart ssh

Уровень 2: Fail2ban против брутфорса

Fail2ban анализирует логи и банит IP-адреса, которые совершают подозрительные действия (например, 5 неудачных входов в админку подряд).

Установка и настройка

sudo apt update
sudo apt install fail2ban -y
sudo systemctl enable fail2ban

Защита SSH

Создайте файл /etc/fail2ban/jail.local:

[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600

Защита WordPress (wp-login.php)

Создайте фильтр /etc/fail2ban/filter.d/wordpress.conf:

[Definition]
failregex = ^<HOST> .* "POST /wp-login.php
ignoreregex =

Добавьте jail в /etc/fail2ban/jail.local:

[wordpress]
enabled = true
port = http,https
filter = wordpress
logpath = /var/log/nginx/access.log
maxretry = 5
bantime = 86400
findtime = 300
sudo systemctl restart fail2ban
sudo fail2ban-client status wordpress

Уровень 3: Ограничение запросов в Nginx (Rate Limiting)

Fail2ban реагирует постфактум. Nginx Rate Limiting отсекает атаки на уровне веб-сервера, не допуская их до PHP-FPM и базы данных.

Настройка зон ограничения

В файле /etc/nginx/nginx.conf в блок http { ... } добавьте:

http {
    # Лимит для авторизации (1 запрос в секунду с одного IP)
    limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
    
    # Лимит для всего сайта (10 запросов в секунду)
    limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
    
    # Лимит для API и xmlrpc (2 запроса в секунду)
    limit_req_zone $binary_remote_addr zone=api:10m rate=2r/s;
    
    # ... остальные настройки
}

Применение лимитов в конфиге сайта

В вашем конфиге /etc/nginx/sites-available/wordpress добавьте правила:

server {
    # Общий лимит для сайта
    limit_req zone=general burst=20 nodelay;

    # Жесткий лимит для wp-login.php
    location = /wp-login.php {
        limit_req zone=login burst=2 nodelay;
        include fastcgi_params;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    # Блокировка xmlrpc.php (если не используете мобильное приложение)
    location = /xmlrpc.php {
        deny all;
        return 444;
    }

    # Лимит для REST API
    location ~ ^/wp-json/ {
        limit_req zone=api burst=5 nodelay;
        include fastcgi_params;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}
sudo nginx -t
sudo systemctl reload nginx

Уровень 4: Cloudflare (Защита от DDoS и скрытие IP)

Если на сервер идет мощная DDoS-атака, ни Nginx, ни Fail2ban не справятся — канал будет забит. Cloudflare принимает удар на себя.

1. Подключение домена

Зарегистрируйтесь на Cloudflare, добавьте домен custom-code.ru и замените NS-серверы у вашего регистратора.

2. Настройка Firewall Rules (бесплатно)

В панели Cloudflare перейдите в Security → WAF → Firewall Rules и создайте правила:

  • Блокировка стран: Если ваш сайт только для РФ/СНГ, заблокируйте весь остальной мир (Country is not in [RU, BY, KZ…]).
  • Защита wp-login: If URI contains wp-login.php AND Threat Score is greater than 10 → Challenge (Captcha).

3. Критически важно: передача реального IP в Nginx

Если вы подключите Cloudflare, Nginx и Fail2ban будут видеть только IP-адреса Cloudflare. При срабатывании Fail2ban заблокирует весь Cloudflare, и ваш сайт упадет для всех.

Скачайте актуальные IP Cloudflare и настройте Nginx:

# Создаем файл с IP Cloudflare
curl -s https://www.cloudflare.com/ips-v4 > /etc/nginx/cloudflare_ips.txt
curl -s https://www.cloudflare.com/ips-v6 >> /etc/nginx/cloudflare_ips.txt

В начало конфига сайта добавьте:

# Чтение IP Cloudflare
include /etc/nginx/cloudflare_ips.txt; # (формат файла нужно будет привести к set_real_ip_from)

# Правильный способ через модуль real_ip:
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
# ... добавьте все подсети из ips-v4
real_ip_header CF-Connecting-IP;

Уровень 5: Внутренняя защита WordPress

Помимо серверной защиты, нужно закрыть уязвимости внутри самого движка.

1. Отключение редактирования файлов в админке

Добавьте в wp-config.php:

define( 'DISALLOW_FILE_EDIT', true );

2. Скрытие версии WordPress

Добавьте в functions.php дочерней темы:

remove_action( 'wp_head', 'wp_generator' );
function remove_wp_version_strings( $src ) {
    global $wp_version;
    parse_str( parse_url( $src, PHP_URL_QUERY ), $query );
    if ( ! empty( $query['ver'] ) && $query['ver'] === $wp_version ) {
        $src = remove_query_arg( 'ver', $src );
    }
    return $src;
}
add_filter( 'style_loader_src', 'remove_wp_version_strings' );
add_filter( 'script_loader_src', 'remove_wp_version_strings' );

3. Правильные права на файлы

Как мы разбирали в статье про ошибку 500, неправильные права — частая причина взлома. Выполните:

sudo find /var/www/wordpress -type d -exec chmod 755 {} \;
sudo find /var/www/wordpress -type f -exec chmod 644 {} \;
sudo chown -R www-data:www-data /var/www/wordpress

Чек-лист безопасности

  • ✅ Вход по SSH только по ключам, root отключен
  • ✅ Fail2ban настроен на SSH и wp-login.php
  • ✅ Nginx Rate Limiting ограничивает частоту запросов
  • ✅ xmlrpc.php заблокирован (если не нужен)
  • ✅ Подключен Cloudflare, настроены Firewall Rules
  • ✅ Nginx корректно определяет реальный IP через CF-Connecting-IP
  • ✅ Редактирование файлов в админке отключено
  • ✅ Права на файлы 644, на папки 755
  • ✅ Все плагины и ядро WordPress обновлены

Что делать, если проблемы не решаются?

Fail2ban банит легитимных пользователей

Проверьте, не слишком ли агрессивны настройки maxretry и findtime. Если вы используете Cloudflare, убедитесь, что Nginx передает реальный IP (иначе бан прилетит всем посетителям с одного IP Cloudflare).

Сайт отдает 503 Service Unavailable

Если вы настроили Rate Limiting и видите ошибку 503, значит, лимиты слишком жесткие для вашего трафика. Увеличьте параметр burst в директиве limit_req.

После подключения Cloudflare сайт работает медленно

Убедитесь, что в Cloudflare включено кэширование статики (Caching → Configuration → Caching Level: Standard). Также проверьте, что SSL-режим установлен в Full (Strict), иначе будут циклические редиректы или ошибки 521/522.

Итог

Безопасность — это не плагин «Wordfence», который ест 200 МБ оперативной памяти и замедляет сайт. Это грамотная настройка сервера. Fail2ban + Nginx Rate Limit + Cloudflare создают эшелонированную защиту, которая не нагружает PHP и MySQL, оставляя ваш сайт быстрым и недоступным для ботов.