VPS с WordPress чаще всего атакуют не «на уровне сайта», а на уровне доступа к серверу и веб-сервисам: пробуют подобрать пароли по SSH, перебирают входы в панель управления, стучатся в стандартные страницы входа WordPress, атакуют XML-RPC и ищут уязвимые версии. В результате страдает не только сайт, но и инфраструктура: если злоумышленник получает доступ к серверу, дальше он может менять файлы, перехватывать трафик и добывать секреты.
Безопасность на VPS обычно собирают из нескольких слоёв: сетевой фильтрации (firewall), строгого доступа по SSH (ключи SSH вместо паролей) и автоматической блокировки подозрительных IP (fail2ban для WordPress). Эти меры не требуют «магии», но требуют дисциплины: сначала ограничить входы, затем перестроить SSH, потом включить fail2ban и проверить логи.
Ниже — рабочий план шаг за шагом. Он рассчитан на типичный VPS под WordPress с Ubuntu/Debian и веб-сервером Nginx или Apache.
Firewall для VPS: закрываем лишние порты и фиксируем правила
Первый шаг — понять, какие порты реально нужны вашему WordPress. Обычно это:
- 22/TCP для SSH (если вы используете SSH);
- 80/TCP и/или 443/TCP для HTTP/HTTPS;
- 25/TCP или 587/TCP, если вы отправляете письма с сервера (часто это не нужно, потому что используют отдельный SMTP);
- дополнительные порты только при наличии конкретных сервисов (например, Redis на localhost, но не наружу).
Если порт нужен только локально, его лучше слушать на 127.0.0.1 или внутренней сети. Тогда firewall не будет тратить силы на фильтрацию «интернета» и снизит поверхность атаки.
Включение firewall на Ubuntu/Debian через UFW
UFW удобен для старта и хорошо читается. Перед применением правил убедитесь, что у вас есть доступ по SSH и вы не заблокируете его случайно.
- Убедитесь, что UFW установлен и включен в безопасном режиме:
«`bash sudo ufw status sudo ufw default deny incoming sudo ufw default allow outgoing «`
- Разрешите SSH и веб-трафик:
«`bash sudo ufw allow 22/tcp sudo ufw allow 80/tcp sudo ufw allow 443/tcp «`
- Включите UFW:
«`bash sudo ufw enable sudo ufw status verbose «`
- Проверьте, что правило SSH действительно активировано. Частая ошибка — разрешить не тот порт, если SSH меняли с 22 на другой.
Ограничение SSH по IP: полезная надстройка
Если у вас есть статический IP (или небольшой диапазон) с которого вы администрируете, добавьте ограничение. Это не отменяет ключи SSH, но резко снижает количество попыток подбора.
Пример (подставьте ваш IP): «`bash sudo ufw allow from X.X.X.X to any port 22 proto tcp sudo ufw delete allow 22/tcp «`
Если администрируете из нескольких мест, лучше разрешить диапазоны, чем открывать порт всем.
Альтернатива: nftables вместо UFW
Если у вас уже есть nftables или вы хотите больше контроля, структура будет похожей: сначала политика deny incoming, затем allow для нужных портов. Главное — не путать цепочки для входящих и пересылки пакетов (forward). Для VPS обычно достаточно входящих цепочек.
Если вы не уверены в конфигурации nftables, оставайтесь на UFW: для большинства WordPress-сценариев его достаточно, чтобы закрыть базовые векторы.
Не забудьте про «двойную» защиту на уровне провайдера
Многие облачные панели (серверные группы безопасности, firewall в панели) уже фильтруют входящий трафик. Это не заменяет UFW, но влияет на итоговую картину. В практике встречаются ситуации, когда:
- UFW разрешает 22, но провайдер блокирует;
- провайдер разрешает всё, а вы думаете, что включили UFW и «оно само защитило».
Проверьте правила в панели и совпадение с UFW. Вы быстрее найдете проблему, если смотреть на оба уровня.
Ключи SSH: заменяем пароли, закрываем root и закрепляем доступ
SSH — типовая цель для автоматических сканеров. Пароли перебирают постоянно, и даже сложный пароль не спасает от ошибок вроде утечки в логах, повторного использования и угадывания по утечкам. Надежный стандарт для VPS: вход только по ключам SSH, плюс ограничения на пользователя и роль.
Переход на ключи SSH без потери доступа
Лучше сделать так, чтобы на момент включения запрета паролей у вас уже был рабочий ключ.
- На вашем компьютере сгенерируйте ключ:
«`bash ssh-keygen -t ed25519 -a 64 «`
- Скопируйте публичный ключ на сервер:
«`bash ssh-copy-id -i ~/.ssh/ided25519.pub user@IPВAШЕГО_СЕРВЕРА «`
Если ssh-copy-id не работает, можно добавить содержимое ключа в файл:
- на сервере: ~/.ssh/authorized_keys
- с правильными правами.
- Проверьте вход по ключу:
«`bash ssh -i ~/.ssh/ided25519 user@IPВAШЕГО_СЕРВЕРА «`
Жесткая настройка sshd_config
Откройте конфигурацию SSH:
- Ubuntu/Debian: /etc/ssh/sshd_config
Дальше применяйте точечные правила. Комбинация обычно выглядит так:
«`bash sudo nano /etc/ssh/sshd_config «`
Рекомендуемые директивы: «`text Port 22 Protocol 2
PermitRootLogin no PasswordAuthentication no KbdInteractiveAuthentication no ChallengeResponseAuthentication no
PubkeyAuthentication yes AuthorizedKeysFile .ssh/authorized_keys
UsePAM yes AllowUsers user1 user2
X11Forwarding no AllowTcpForwarding no PermitTunnel no «`
Несколько замечаний:
- PermitRootLogin no убирает классический путь входа под root.
- PasswordAuthentication no отключает перебор паролей.
- AllowUsers ограничивает список пользователей, которые вообще могут логиниться.
- Если вам нужен проброс портов или туннели, не отключайте AllowTcpForwarding без проверки: некоторым сценариям это действительно нужно.
Перед перезапуском проверьте конфиг: «`bash sudo sshd -t sudo systemctl reload sshd «`
Если sshd -t показывает ошибку, не делайте reload. Иначе можно потерять доступ, если конфиг некорректный.
Минимизируем шанс «не того» ключа: права на .ssh
Частая проблема после включения PasswordAuthentication no — сервер игнорирует ключ. Причина почти всегда в правах файлов.
Проверьте: «`bash sudo chmod 700 ~user/.ssh sudo chmod 600 ~user/.ssh/authorized_keys «`
И проверьте владельца: каталог и файлы должны принадлежать вашему пользователю, а не root.
Смена порта: опция, а не защита
Иногда меняют Port с 22 на другой, чтобы снизить количество баннерных сканов. Это не безопасность как таковая: сканеры находят открытые порты автоматически. Но как дополнительный слой для уменьшения шума — имеет смысл, если вы аккуратно обновите правила firewall и команды подключения.
Если вы меняете Port, сначала обновите UFW (разрешите новый порт), потом меняйте sshd_config. И только затем отключайте парольный вход.
fail2ban для WordPress: как блокировать переборы и шум по логам
fail2ban работает по принципу: читает логи, ищет характерные паттерны (подбор пароля, повторные ошибки, атаки на конкретные URL) и автоматически добавляет IP в блокировку на короткое время. Сценарий особенно полезен для SSH, но для WordPress он тоже помогает: уменьшается количество повторяющихся запросов на вход, XML-RPC и подозрительные попытки.
Установка fail2ban
На Debian/Ubuntu: «`bash sudo apt update sudo apt install -y fail2ban «`
Проверьте статус: «`bash sudo systemctl status fail2ban «`
Базовая настройка: используем фильтры и jail
Основной конфиг обычно в:
- /etc/fail2ban/jail.local
- фильтры: /etc/fail2ban/filter.d/
Создайте jail.local и начните с SSH. Даже если фокус статьи WordPress, без SSH-части картина неполная: часть атак всегда начинается с попытки входа на сервер.
Пример для SSH (в jail.local): «`ini [sshd] enabled = true port = ssh logpath = /var/log/auth.log maxretry = 5 findtime = 10m bantime = 1h «`
После правок: «`bash sudo systemctl restart fail2ban sudo fail2ban-client status «`
Команды для диагностики:
- fail2ban-client status sshd
- fail2ban-client status
- tail -n 200 /var/log/fail2ban.log
Типичная ошибка: смотреть не тот logpath. На некоторых системах лог авторизации может идти в /var/log/secure. Если jail не срабатывает, первым делом проверьте путь к логам.
WordPress jail для Nginx или Apache
У fail2ban есть готовые фильтры для некоторых популярных веб-ошибок, но чаще всего вы описываете правила под свои URL и шаблоны. Для WordPress нас интересуют:
- попытки доступа к wp-login.php и wp-admin (особенно массовые повторения);
- атаки на wp-json, если они бьют в подбор endpoint’ов;
- XML-RPC (wp/xmlrpc.php) — частая цель для brute force;
- подозрительные строки User-Agent и частые 401/403/404 по одним и тем же путям (аккуратно, иначе можно заблокировать легитимных пользователей с ошибкой доступа).
Пример: jail для Nginx
Допустим, у вас Nginx пишет логи в /var/log/nginx/access.log. Тогда за основу можно взять такой шаблон:
«`ini [wordpress-login] enabled = true port = http,https filter = nginx-http-auth logpath = /var/log/nginx/access.log maxretry = 10 findtime = 10m bantime = 4h «`
Однако nginx-http-auth ориентирован на конкретный паттерн авторизации. Для WordPress часто удобнее свой фильтр по URL. Тогда создайте фильтр в /etc/fail2ban/filter.d/wordpress-login.conf.
Пример фильтра (упрощенная логика по wp-login.php и wp-admin): «`ini [Definition] failregex = ^<HOST> -.»(GET|POST) /(wp-login\.php|wp-admin).» 4\d\d ignoreregex = «`
Дальше jail: «`ini [wordpress-login] enabled = true port = http,https filter = wordpress-login logpath = /var/log/nginx/access.log maxretry = 8 findtime = 15m bantime = 6h «`
Почему bantime разумный: атаки по WordPress часто массовые, и блокировать на 5–30 минут иногда мало. Но слишком длинный ban (например, на сутки) может привести к проблемам, если у вас есть боты проверок или корпоративный прокси с общим IP.
Пример: отдельный jail для XML-RPC
XML-RPC часто атакуют переборами. Для WordPress он может быть полезен, но если вы его не используете, рационально отключать на уровне WordPress. Если не хотите отключать полностью, fail2ban можно настроить на частые ошибки доступа.
Фильтр под XML-RPC: «`ini [Definition] failregex = ^<HOST> -.»(GET|POST) /wp-xmlrpc\.php.» 4\d\d «`
Jail: «`ini [wordpress-xmlrpc] enabled = true port = http,https filter = wordpress-xmlrpc logpath = /var/log/nginx/access.log maxretry = 6 findtime = 10m bantime = 12h «`
Здесь важно смотреть на ваш лог: иногда XML-RPC атаки заканчиваются 404, иногда 403, иногда 200 при ошибках на стороне WordPress. Если fail2ban вообще не срабатывает, подстройте failregex под фактические коды.
Для Apache логика похожа, но пути и шаблоны другие
Если Apache:
- logpath обычно /var/log/apache2/access.log (или /var/log/apache/access.log, зависит от дистрибутива);
- failregex подбирайте по тому, как Apache пишет строки.
Самый быстрый путь: найти в логах реальные строки атак. Затем взять несколько типичных примеров и собрать шаблон. Лучше 3-5 точных паттернов, чем один «универсальный», который случайно совпадет с нормальными запросами.
Как проверить, что fail2ban реально работает
После настройки всегда делайте минимум три проверки:
1. Убедитесь, что jail включен:
«`bash sudo fail2ban-client status wordpress-login «`
2. Посмотрите статистику:
«`bash sudo fail2ban-client status sudo tail -n 100 /var/log/fail2ban.log «`
3. Сымитируйте событие локально (осторожно): сделайте несколько запросов к wp-login.php с «не тем» путём или вызовите ошибки, и посмотрите, появится ли бан.
Если бан не ставится, обычно причина:
- неверный logpath;
- слишком жесткий failregex;
- коды ответов не те (например, у вас 200 вместо 403/404);
- fail2ban не видит лог (права на чтение, rotatelogs, изменения формата).
Вокруг fail2ban и SSH: что дополнительно стоит сделать именно для WordPress
firewall, ключи SSH и fail2ban закрывают значимую часть атак. Но WordPress как приложение тоже требует базовой гигиены, иначе вы можете заблокировать шум, но не проблему в корне.
Обновления и контроль версий
Регулярно обновляйте:
- ядро WordPress;
- плагины;
- темы;
- PHP и веб-сервер.
Проверка раз в неделю по логам и в админке часто эффективнее, чем «раз в квартал», когда вы потом отлавливаете сразу несколько несовместимых версий.
Если вы обновляете плагины массово, делайте это после резервной копии и на тестовой копии сайта, если она есть. На VPS с одним сервером иногда выбирают схему: обновлять по одному, смотреть логи и только потом двигаться дальше.
Права на файлы и запрет записи лишним
WordPress должен писать в ограниченные директории (обычно это wp-content). Если вы заметили, что права на файлы слишком свободные, атакующий при компрометации получает больше возможностей.
Практический подход:
- директории wp-content/uploads обычно должны допускать запись;
- остальные файлы лучше держать так, чтобы веб-пользователь только читал.
Точная схема зависит от пользователя веб-сервера (www-data, nginx) и модели размещения, но принцип один: меньше прав на запись там, где они не нужны.
Отключение XML-RPC, если он не используется
Многие сайты не пользуются XML-RPC. Если это ваш кейс, отключение часто снижает количество попыток атак и разгружает fail2ban (меньше событий — меньше банов и меньше ложных совпадений).
Если вы используете сторонние инструменты, которые требуют XML-RPC (например, старые приложения), отключение может повлиять на синхронизацию. Тогда компромисс — оставить включенным, но усилить защиту fail2ban и ограничить доступ сетевыми правилами.
Ограничение запросов на уровне веб-сервера
rate limiting в Nginx (limit_req) или модули в Apache могут дополнительно снизить нагрузку от переборов, даже если fail2ban еще не успел забанить. Это особенно полезно при высоком шуме: fail2ban банит после накопления событий, а rate limiting срабатывает сразу на частоту.
Если вы используете Nginx, типичный принцип такой: ограничивать слишком частые запросы к wp-login.php и xmlrpc.php, при этом не трогать общий трафик сайта.
Логи и контроль событий
WordPress в связке с VPS должен иметь понятный набор логов:
- access.log и error.log веб-сервера;
- auth.log для SSH;
- лог fail2ban;
- логи обновлений/cron, если вы используете.
Когда вы настраиваете firewall и fail2ban, вы фактически «закрываете дверь». Но чтобы понять, насколько она помогает, нужно время от времени смотреть, какие события приходят до блокировок. Иногда оказывается, что баните не тех: например, слишком жестко реагируете на 401/403, получая блокировки валидного бота мониторинга.
Практический чек-лист внедрения: порядок действий и типичные ошибки
Чтобы внедрение не превратилось в риск потери доступа, работайте по порядку и проверяйте на каждом этапе.
Порядок внедрения
- Уточните нужные порты и временно включите firewall так, чтобы вы не потеряли SSH.
- Настройте ключи SSH и проверьте вход по ключу до запрета паролей.
- В sshd отключите PasswordAuthentication и PermitRootLogin.
- Включите fail2ban: сначала sshd jail, затем WordPress jails под ваши логи.
- Проверьте fail2ban-client status, затем tail /var/log/fail2ban.log.
- Настройте дополнительные меры для WordPress: обновления, права, при необходимости ограничение XML-RPC и rate limiting.
Типичные ошибки, которые встречаются чаще всего
- Отключили PasswordAuthentication no, но забыли добавить ключ в authorized_keys для нужного пользователя. Результат: только отказ.
- Настроили firewall так, что разрешили 22, но SSH переехал на другой port. Результат: «пустой экран» вместо доступа.
- Поставили fail2ban с неверным logpath: jail «включен», но события не парсятся.
- Использовали слишком общий failregex, и fail2ban начинает банить легитимные пользователей. Проверяйте несколько дней поведение и корректируйте правила.
- Оставили root как разрешенного пользователя. Это ускоряет автоматизированные сценарии пробора, даже если passwordauth отключен (иногда пробуют другие способы и исследуют поверхность).
Как безопасно откатываться
Сведите изменения в конфиги так, чтобы откат был быстрым:
- делайте копии jail.local и sshd_config;
- используйте systemctl reload, а не полные рестарты, где это возможно;
- перед перезапуском sshd делайте sshd -t.
Если что-то пошло не так, чаще всего проще откатить конфиг, чем «гадать», где ошибка. А «гадание» на SSH — прямой путь к потере доступа.
Итог: безопасность VPS под WordPress как система, а не набор случайных правил
firewall ограничивает сеть и уменьшает количество точек входа. ключи SSH делают доступ предсказуемым: сервер принимает только то, что вы явно разрешили, и перестает быть площадкой для перебора паролей. fail2ban для WordPress закрывает повторяющийся шум по логам и помогает быстрее реагировать на массовые попытки атак.
Если вы хотите получить максимальный эффект, внедряйте меры последовательно и проверяйте по логам: сначала доступ (SSH и firewall), затем автоматические баны (fail2ban) и только после этого переходите к «тонкой настройке» под WordPress (XML-RPC, rate limiting, правки фильтров по конкретным строкам логов). Такой порядок снижает риск и ускоряет получение результата.
С чего начать прямо сейчас: откройте текущие правила firewall, проверьте sshd_config на наличие PasswordAuthentication no и PermitRootLogin no, затем посмотрите, что fail2ban уже банит (или не банит) в ваших логах. Сделайте по одному изменению, подтверждайте статус командой fail2ban-client status и держите SSH доступ до тех пор, пока изменения не станут устойчивыми.
