Каждый день боты методично перебирают пароли к тысячам WordPress-сайтов - и ваш не исключение. Стандартный адрес входа в административную панель известен всем: /wp-admin и /wp-login.php публичны по умолчанию, и любой желающий может попробовать туда попасть. Я занимаюсь веб-разработкой с 2013 года, руковожу студией «Мельница» (melnyca.ru), и за это время видел сотни сайтов, взломанных именно через брутфорс формы входа. Закрыть доступ к wp-admin посторонним - это первое, что я делаю на любом новом проекте. Block access к административной зоне на уровне сервера снижает нагрузку, убирает целый класс атак и не требует сторонних плагинов.
В этой статье разберём три подхода: ограничение через .htaccess для Apache, настройку nginx и PHP-код в functions.php. Также рассмотрим HTTP-аутентификацию как дополнительный рубеж защиты. Каждый метод подходит для разных ситуаций - в зависимости от вашего хостинга и уровня доступа к серверу. Статья рассчитана на владельцев WordPress-сайтов и вебмастеров; если вы работаете с другими CMS - логика похожа, но конкретные настройки отличаются.
Почему стандартная защита WordPress недостаточна

WordPress из коробки защищает административную панель только одним рубежом - формой входа с логином и паролем. Казалось бы, этого достаточно: поставил сложный пароль, и всё. Но проблема в том, что сама форма входа остаётся публичной и доступна любому адресу в интернете. Боты знают об этом и активно этим пользуются.
Типичная картина на среднестатистическом WordPress-сайте без дополнительной блокировки: сотни запросов в сутки к /wp-login.php, автоматический перебор связок логин-пароль, сканирование xmlrpc.php. Всё это создаёт нагрузку на сервер, засоряет логи и рано или поздно приводит к успешному взлому - особенно если где-то используется слабый пароль или устаревший плагин с уязвимостью.
Концепция «двойной защиты» решает эту проблему иначе. Первый слой - серверный: запрос от постороннего IP просто не доходит до WordPress, сервер возвращает 403 или перенаправляет на другую страницу. Второй слой - штатная аутентификация WordPress для тех, кому доступ разрешён. Держать wp-admin публичным - всё равно что оставлять входную дверь офиса открытой в расчёте на то, что замок на сейфе внутри достаточно надёжен.
В текущей реальности угроза брутфорса и сканирования особенно актуальна для сайтов на популярных CMS. WordPress занимает больше 40% рынка, а значит, боты заточены именно под него. Стандартные меры - сложный пароль, капча, ограничение попыток входа через плагины - полезны, но работают уже после того, как запрос дошёл до PHP. Серверная блокировка не даёт запросу дойти вообще. Именно поэтому block access на уровне веб-сервера я считаю обязательным шагом, а не опциональным.
Как закрыть wp-admin через .htaccess (Apache)
Если ваш сайт работает на Apache (большинство виртуальных хостингов), самый простой и надёжный способ - создать файл .htaccess прямо в папке /wp-admin. Важный момент: этот файл создаётся именно в папке wp-admin, а не в корне сайта. Тогда правила применяются только к административной зоне и не затрагивают остальной сайт.
Базовая инструкция:
- Подключитесь к серверу через FTP, cPanel или SSH.
- Перейдите в папку /wp-admin.
- Создайте файл .htaccess (или откройте существующий).
- Добавьте следующий код, заменив IP на ваш реальный адрес.
Сценарий 1: разрешить доступ только с вашего IP, всем остальным - deny from:
Order deny,allow
Deny from all
Allow from 123.456.789.0 Сценарий 2: заблокировать конкретные IP-адреса (например, источники атак), остальным оставить доступ:
Order allow,deny
Allow from all
Deny from 111.222.333.0
Deny from 555.666.777.0 Важное предупреждение: если у вас динамический IP (меняется при каждом подключении), первый сценарий заблокирует и вас самих после смены адреса. В таком случае либо используйте диапазон подсети (например, 123.456.789), либо совмещайте IP-блокировку с HTTP-аутентификацией - об этом расскажу дальше.
Синтаксис директив отличается в зависимости от версии Apache. Делать вид, что этой разницы не существует, нельзя - неправильный синтаксис либо не сработает, либо сломает сайт целиком:
| Параметр | Apache 2.2 | Apache 2.4 |
| Запретить всем | Deny from all | Require all denied |
| Разрешить IP | Allow from 1.2.3.4 | Require ip 1.2.3.4 |
| Порядок обработки | Order deny,allow | не нужен (RequireAny/RequireAll) |
| Где используется | Старые хостинги | Современные серверы |
Проверить версию Apache можно командой apache2 -v по SSH или запросив поддержку хостинга. На большинстве современных серверов уже Apache 2.4, поэтому для текущей конфигурации предпочтителен синтаксис с Require. После сохранения файла проверьте доступ к /wp-admin с разрешённого IP и с другого адреса (например, через мобильный интернет) - убедитесь, что блокировки работают именно так, как задумано.
Как закрыть wp-admin в nginx
В nginx логика блокировки отличается от Apache: здесь нет .htaccess, все правила прописываются в конфигурационном файле сервера - обычно в блоке server внутри /etc/nginx/sites-available/your-site.conf.
Базовый location-блок для закрытия wp-admin по IP выглядит так:
location ~ ^/wp-admin {
allow 95.142.45.10;
deny all;
}
location = /wp-login.php {
allow 95.142.45.10;
deny all;
} Здесь важен порядок директив: nginx проверяет allow/deny сверху вниз и применяет первое совпадение. Если ваш IP стоит перед deny all - вы пройдёте, все остальные получат 403.
Критический нюанс, который ломает сайты: нельзя блокировать admin-ajax.php. Этот файл находится в папке wp-admin, но используется для AJAX-запросов на фронтенде - формы, корзина WooCommerce, динамические блоки. Если применить block access ко всей папке без исключения, плагины начнут молча ломаться. Правильный вариант:
location = /wp-admin/admin-ajax.php {
allow all;
}
location ~ ^/wp-admin {
allow 95.142.45.10;
deny all;
}
location = /wp-login.php {
allow 95.142.45.10;
deny all;
} Блок с admin-ajax.php должен стоять выше общего правила для wp-admin - иначе общее правило перехватит запрос раньше. После правок не забудьте сделать nginx -t для проверки синтаксиса и systemctl reload nginx для применения изменений.
Если у вас динамический IP - добавьте несколько адресов через отдельные строки allow, либо используйте вместо IP-блокировки метод с HTTP-аутентификацией, о котором расскажу ниже.
Как ограничить доступ через PHP в functions.php
Если у вас нет доступа к конфигурации сервера - shared-хостинг без SSH, панель управления без редактора nginx - можно сделать блокировки на уровне WordPress через хук init. Это не так надёжно, как серверные методы, но лучше, чем ничего.
Базовый сниппет выглядит так:
add_action( 'init', function() {
if ( is_admin() && ! current_user_can( 'manage_options' ) ) {
wp_die( 'Доступ запрещён', 403 );
}
}); Разберём построчно: add_action( 'init', ... ) запускает функцию на каждый запрос после загрузки WordPress. is_admin() проверяет, что запрос идёт в зону /wp-admin. current_user_can( 'manage_options' ) - проверка роли: только администраторы пройдут дальше. Остальные получат экран с ошибкой.
Теперь про проблему, на которую я наступал сам: наивная реализация ломает выход из системы. Когда пользователь кликает «Выйти», WordPress обрабатывает запрос через wp-login.php?action=logout, но промежуточный редирект может проходить через зону is_admin() - и сниппет его обрежет. Пользователь зависнет в сессии. Правильный вариант с защитой от этого:
add_action( 'init', function() {
if ( is_admin()
&& ! current_user_can( 'manage_options' )
&& ! wp_doing_ajax()
&& ! ( isset( $_GET['action'] ) && $_GET['action'] === 'logout' )
) {
wp_die( 'Доступ запрещён', 403 );
}
}); Функция wp_doing_ajax() исключает AJAX-запросы - без этого комментарий к записи через форму на фронтенде может не отправиться. Проверка action=logout сохраняет работоспособность выхода из системы.
Механизм простой: exit add action - хук 'init' срабатывает до отрисовки страницы, wp_die() завершает скрипт с кодом 403. Куда вставлять: в functions.php вашей темы или, лучше, в отдельный плагин-сниппет (например, через Code Snippets). Редактировать functions.php напрямую рискованно - одна синтаксическая ошибка в PHP закроет весь сайт.
Дополнительный рубеж: HTTP-аутентификация для wp-admin
HTTP Basic Auth - это второй пароль на уровне сервера, до того как WordPress вообще загрузится. Браузер показывает системное окно с запросом логина и пароля - боты его не проходят, потому что не умеют с ним взаимодействовать. Этот метод особенно полезен, когда у вас динамический IP и белый список адресов не подходит.
Шаг 1. Создайте файл .htpasswd с хешированным паролем. Проще всего через утилиту htpasswd:
htpasswd -c /etc/nginx/.htpasswd andrey Или используйте онлайн-генератор - он выдаст строку вида andrey:$apr1$xyz.... Файл нельзя класть в корень сайта - только за пределами webroot или в место, недоступное напрямую через браузер.
Шаг 2. Для Apache - пропишите в .htaccess папки wp-admin:
AuthType Basic
AuthName "Admin Area"
AuthUserFile /etc/apache2/.htpasswd
Require valid-user Для nginx - добавьте в location-блок:
location ~ ^/wp-admin {
auth_basic "Admin Area";
auth_basic_user_file /etc/nginx/.htpasswd;
allow all;
} И снова тот же нюанс про admin-ajax.php: его нужно исключить из BasicAuth, иначе AJAX-запросы плагинов будут падать с 401. Добавьте отдельный location выше с auth_basic off.
Из практики студии: на одном проекте мы комбинировали IP-ограничение с BasicAuth - сначала allow from для офисного IP, а для работы с телефона (динамический адрес) - пароль. Это дало гибкость без потери безопасности.
Сравнение трёх методов защиты wp-admin:
| Метод | Сложность настройки | Зависимость от IP | AJAX-совместимость | Надёжность |
| .htaccess + IP (Apache) | Низкая | Да - нужен статический IP | Требует исключения admin-ajax.php | Высокая |
| nginx location + IP | Средняя | Да - нужен статический IP | Требует отдельного location | Высокая |
| HTTP Basic Auth (.htpasswd) | Средняя | Нет - работает с любым IP | Требует исключения admin-ajax.php | Очень высокая |
Самая частая ошибка при deny from / allow from - забыть про admin-ajax.php. Я видел, как после таких блокировок переставали работать формы обратной связи, слайдеры и целые страницы оформления заказа - и клиент несколько часов не понимал, что причина в защите wp-admin.
Типичные ошибки и что делать дальше
За годы практики вижу три ошибки, которые повторяются чаще всего.
- Динамический IP. Закрыли доступ по IP - утром провайдер выдал новый адрес, и вы сами оказались за бортом. Решение: используйте статический IP или заранее добавьте резервный доступ через VPN с фиксированным адресом.
- Забыли admin-ajax.php. Плагины, формы, публичную часть сайта - всё, что работает через AJAX, сломается, если заблокировать весь каталог wp-admin без исключения. Обязательно добавляйте правило, разрешающее запросы к admin-ajax.php для всех.
- Синтаксис .htaccess. Одна лишняя буква - и сайт падает с ошибкой 500. Не паникуйте: зайдите через FTP или файловый менеджер cPanel, откройте .htaccess и удалите последний блок правил. Сайт поднимется за секунды. Перед любой правкой делайте резервную копию файла.
По выбору метода: если есть статический IP - блокировка на уровне .htaccess - самый надёжный вариант. Нет статического IP или работаете с разных мест - установите плагин с белым списком и включите двухфакторную аутентификацию (2FA, например через WP 2FA или Google Authenticator for WP). Для большинства небольших сайтов связка из смены URL входа и 2FA закрывает 95% атак без танцев с настройкой сервера.
Комментарий напоследок: ни один из этих методов не заменяет регулярные обновления WordPress и плагинов. Защита входа - первый рубеж, но не единственный.
Эта статья основана на личном опыте автора и актуальна на момент публикации. Интерфейсы сервисов и алгоритмы поисковых систем регулярно меняются - рекомендую проверять актуальность инструкций на официальных ресурсах. Если у вас остались вопросы - задайте их в комментариях.
Список литературы
- WordPress Documentation Team - Hardening WordPress // Developer.WordPress.org (Advanced Administration Handbook)
- Nginx, Inc. - Module ngx_http_access_module // nginx.org (официальная документация)
- Apache Software Foundation - Access Control. Apache HTTP Server Version 2.4 // httpd.apache.org, 2024
- Команда offlineCRM - Взламывают сайты после выхода статей. Пишем подробно, как защитить ваш сайт на WordPress // Habr, 2022







