.htaccess для WordPress
WordPress активно использует .htaccess: стандартный блок # BEGIN WordPress обеспечивает «красивые URL» (ЧПУ), а дополнительные правила закрывают wp-config.php, ограничивают wp-login.php и xmlrpc.php, запрещают выполнение PHP в папке загрузок, ставят кэш и заголовки безопасности. Ниже — полный разбор: готовые блоки, объяснение «почему» и типичные грабли. Если что-то уже пошло не так — гид «Почему .htaccess не работает»; собрать блок из чекбоксов — генератор; проверить файл — линтер.
Все WP-рецепты здесь — WP-специфика. Общие темы (IP-фильтрация, Basic-auth, заголовки безопасности, блокировка ботов) подробно разобраны в гидах «Безопасность сайта через .htaccess» и «Ускорение сайта через .htaccess»; ошибки и коды — в гиде «Почему .htaccess не работает»; синтаксис правил — в линтере.
1. Стандартный .htaccess WordPress (ЧПУ)
WordPress автоматически записывает в .htaccess блок между маркерами # BEGIN WordPress и # END WordPress при каждом сохранении настроек постоянных ссылок (Permalinks). Этот блок — фронт-контроллер: все запросы к несуществующим файлам и каталогам перенаправляются в index.php, который уже сам строит ответ по маршруту.
Важно: не редактируйте содержимое внутри # BEGIN WordPress … # END WordPress вручную — WP перезапишет при следующем сохранении настроек. Свои правила добавляйте выше или ниже этого блока.
# BEGIN WordPress # Правила ниже генерируются WordPress автоматически. # Не редактируйте между маркерами BEGIN и END вручную. <IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] </IfModule> # END WordPress
- Если сайт в подкаталоге (например,
/blog/), значениеRewriteBaseдолжно совпадать с ним:RewriteBase /blog/. - Блок требует включённого
mod_rewrite. Если ЧПУ дают 404 — проверьте, загружен ли модуль; подробно — /errors/ → раздел 4. - Свои правила (
Redirect,RewriteRule,Header) ставьте выше блока# BEGIN WordPress.
2. Принудительный HTTPS для WordPress
Редирект с http:// на https:// ставится в .htaccess выше блока # BEGIN WordPress. После добавления обязательно обновите адрес сайта в настройках WordPress (Настройки → Общие → Адрес WordPress / Адрес сайта) и добавьте define('FORCE_SSL_ADMIN', true); в wp-config.php для защиты входа в админку.
<IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{HTTPS} off RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L] </IfModule>
Если сайт работает за CDN или обратным прокси (Cloudflare, nginx-реверс), Apache получает трафик уже расшифрованным и %{HTTPS} всегда off — редирект уйдёт в петлю. Используйте заголовок X-Forwarded-Proto:
<IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{HTTP:X-Forwarded-Proto} !https RewriteCond %{HTTPS} off RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L] </IfModule>
- «Бесконечный редирект» после включения HTTPS — типичная проблема за CDN; подробно — /errors/ → раздел 5.
- Не забудьте обновить адрес сайта в настройках WP и в
wp-config.php— иначе WP сам будет редиректить обратно наhttp://.
3. Склейка зеркал (www ↔ без www)
WordPress лучше всего управляет каноническим адресом сайта через Настройки → Общие (Адрес WordPress и Адрес сайта). Если вам всё же нужно сделать склейку на уровне .htaccess — ставьте правила выше блока # BEGIN WordPress.
<IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L] </IfModule>
<IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{HTTP_HOST} !^www\. [NC] RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L] </IfModule>
- Не задавайте склейку одновременно в
.htaccessи в настройках CMS / панели — получите бесконечный редирект. - После смены канонического адреса обновите настройки WordPress и карту сайта.
4. Защита служебных файлов WP
По умолчанию Apache отдаёт любой файл в корне сайта — включая wp-config.php с паролем базы данных, файлы .git, бэкапы и логи. Закройте их явно в .htaccess.
<Files wp-config.php> Require all denied </Files>
# .htaccess и .htpasswd — всегда <FilesMatch "^\.ht"> Require all denied </FilesMatch> # Лишние файлы WP в корне <FilesMatch "^(wp-config-sample\.php|readme\.html|license\.txt)$"> Require all denied </FilesMatch> # Репозитории — на всякий случай RedirectMatch 404 /\.(git|svn|hg)(/|$)
- Блоки выше используют синтаксис Apache 2.4 (
Require all denied). На Apache 2.2 нужен старый синтаксис (Order allow,deny+Deny from all) — конвертировать поможет конвертер 2.2↔2.4. - Проверить, что файл написан без ошибок и правила реально закрывают нужное — линтер .htaccess.
- Подробнее про защиту файлов — /security/ → раздел 2.
5. Отключить / ограничить xmlrpc.php
xmlrpc.php — старый XML-RPC интерфейс WordPress. Он используется мобильным приложением WP, Jetpack и некоторыми плагинами, но также является вектором атак: pingback-DDoS и перебор паролей методом «батарейного» перебора (один запрос = сотни попыток логина). Если Jetpack и мобильное приложение не нужны — закройте полностью.
<Files xmlrpc.php> Require all denied </Files>
Если Jetpack или мобильное приложение используются — разрешите только с нужных IP:
<Files xmlrpc.php> Require ip 203.0.113.0/24 </Files>
- IP серверов Jetpack — динамические; смотрите актуальный список в документации Automattic.
- Pingback можно отключить в настройках WordPress (Настройки → Обсуждение → «Разрешить уведомления с других сайтов») без блокировки всего xmlrpc.
6. Защита wp-login.php от перебора
Страница входа WordPress (wp-login.php) — постоянная цель брутфорс-атак. Первая линия обороны — ограничить к ней доступ по IP.
<Files wp-login.php> Require ip 203.0.113.0/24 Require ip 192.0.2.15 </Files>
Вариант 2 — HTTP Basic Auth поверх формы входа (дополнительный пароль перед тем, как WordPress вообще покажет страницу):
<Files wp-login.php> AuthType Basic AuthName "WordPress Login" AuthUserFile /home/USER/.htpasswd Require valid-user </Files>
AuthUserFile— абсолютный путь; файл.htpasswdкладите вне document root. Сгенерировать — генератор .htpasswd.- Грабли: HTTP Basic на
wp-login.phpможет конфликтовать с AJAX-запросами. Не закрывайте Basic-auth весь/wp-admin/целиком без исключения дляadmin-ajax.php— сломаются виджеты и плагины. - Подробнее про HTTP Basic — статья «Защита папки паролем»; про IP-фильтрацию — статья «Ограничение доступа по IP».
7. Ограничить /wp-admin/ по IP
Закрыть весь каталог /wp-admin/ по IP — эффективная защита, но с обязательным исключением для admin-ajax.php: этот файл обрабатывает AJAX-запросы фронтенда (корзина WooCommerce, поиск, плагины) и должен быть доступен всем.
Создайте файл wp-admin/.htaccess (отдельный файл в каталоге wp-admin, а не в корне сайта):
# Исключение для admin-ajax.php — нужен фронтенду <Files admin-ajax.php> Require all granted </Files> # Всё остальное в wp-admin — только с доверенных IP <RequireAll> Require all granted Require ip 203.0.113.0/24 Require ip 192.0.2.15 </RequireAll>
- Если у вас динамический IP — не забывайте обновлять список при смене; иначе сами не попадёте в админку.
- Подробнее про IP-фильтрацию и синтаксис
Require— статья «Ограничение доступа по IP»; конвертировать из Apache 2.2 — конвертер 2.2↔2.4.
8. Запретить выполнение PHP в wp-content/uploads
Один из главных векторов взлома WordPress: через форму загрузки заливают shell.php в wp-content/uploads/ и запускают его напрямую. Контрмера — запретить выполнение и отдачу PHP-файлов из папки загрузок. Создайте файл wp-content/uploads/.htaccess:
<FilesMatch "\.ph(p[0-9]?|tml|ar)$"> Require all denied </FilesMatch> # Дополнительно — на старых конфигурациях: # RemoveHandler .php .phtml .php3 .php4 .php5 # RemoveType .php .phtml
- Важная грабля: если на сервере разрешён
AllowOverride FileInfoдля каталога uploads, злоумышленник может залить туда собственный.htaccess, отменяющий запрет. Надёжная контрмера —AllowOverride Noneв конфиге сервера для папки uploads (это делает хостер, не вы). - Проверить, что правило написано правильно — линтер .htaccess.
- Подробнее про запрет выполнения PHP — /security/ → раздел 6.
9. Кэш статики и gzip для WordPress
Браузерный кэш и сжатие ускоряют загрузку сайта. Блоки ставятся в корневой .htaccess — можно выше или ниже блока # BEGIN WordPress, но вне него.
<IfModule mod_expires.c> ExpiresActive On ExpiresByType image/jpeg "access plus 1 year" ExpiresByType image/png "access plus 1 year" ExpiresByType image/gif "access plus 1 year" ExpiresByType image/webp "access plus 1 year" ExpiresByType image/svg+xml "access plus 1 year" ExpiresByType text/css "access plus 1 month" ExpiresByType application/javascript "access plus 1 month" ExpiresByType application/x-javascript "access plus 1 month" ExpiresByType font/woff2 "access plus 1 year" ExpiresByType font/woff "access plus 1 year" </IfModule>
<IfModule mod_deflate.c> AddOutputFilterByType DEFLATE text/html text/plain text/css AddOutputFilterByType DEFLATE application/javascript application/x-javascript AddOutputFilterByType DEFLATE application/json application/xml AddOutputFilterByType DEFLATE image/svg+xml font/woff font/woff2 </IfModule>
- Важно: плагины кэширования WordPress (WP Super Cache, W3 Total Cache, LiteSpeed Cache) часто сами записывают в
.htaccessсвои блоки кэша и gzip. Не дублируйте их вручную — конфликтующие директивы могут дать непредсказуемый результат. При удалении плагина — почистите его блоки из.htaccess. - Собрать блоки кэша и gzip из чекбоксов — генератор (блоки «Кэш статики» и «GZIP»); подробный разбор — /performance/.
10. Заголовки безопасности для WordPress
Заголовки безопасности защищают посетителей от кликджекинга и части XSS. Ставятся через mod_headers в корневом .htaccess.
<IfModule mod_headers.c> Header always set X-Frame-Options "SAMEORIGIN" Header always set X-Content-Type-Options "nosniff" Header always set Referrer-Policy "strict-origin-when-cross-origin" # HSTS — только если сайт полностью на HTTPS: # Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" </IfModule>
- CSP в WordPress — осторожно: WordPress использует множество inline-скриптов и стилей в админке и на фронтенде. Строгий
Content-Security-Policyпочти наверняка сломает часть функций (редактор Gutenberg, плагины). Начинайте сContent-Security-Policy-Report-Only, смотрите отчёты в DevTools, и только потом переходите на боевой заголовок. - Подробный разбор каждого заголовка — справочник HTTP-заголовков → безопасность; собрать — генератор.
11. Скрыть версию WordPress и PHP
Версия PHP утекает через заголовок X-Powered-By — уберите его через mod_headers. Версия WordPress утекает через мета-тег generator и параметр ?ver= в URL статики — это убирается в functions.php, не в .htaccess.
<IfModule mod_headers.c> Header always unset X-Powered-By </IfModule>
ServerSignature OffиServerTokens Prod(убрать версию Apache из страниц ошибок) — не работают в.htaccess, только в конфиге сервера или виртхоста; просите хостера.- Убрать
?ver=из URL статики WordPress — через фильтрscript_loader_src/style_loader_srcвfunctions.php: это задача темы / плагина, а не.htaccess.
12. Частые проблемы WordPress + .htaccess
Разбор наиболее частых ситуаций, когда WordPress и .htaccess конфликтуют.
- ЧПУ не работают после переноса / свежей установки. Причины: блок
# BEGIN WordPressотсутствует или неполный;mod_rewriteне включён; неверныйRewriteBase(сайт в подкаталоге). Решение: в админке зайдите в Настройки → Постоянные ссылки и нажмите «Сохранить» — WP перезапишет блок. Если не помогло — /errors/ → раздел 4. - 500 Internal Server Error после установки плагина кэширования. Плагин добавил
php_value/php_flagв.htaccess, а ваш хостинг работает на PHP-FPM — эти директивы дают 500. Удалите строкиphp_value/php_flagили отключите плагин; настройки PHP на FPM задаются через.user.ini. Подробно — /errors/ → раздел 2. - Бесконечный редирект (ERR_TOO_MANY_REDIRECTS). Типично за CDN: HTTPS-правило в
.htaccessпроверяет%{HTTPS} off, но за прокси это всегдаoff. Замените на%{HTTP:X-Forwarded-Proto} !https(см. раздел 2). Или конфликт: WP-настройки тянут наhttps://, а редирект в.htaccess— обратно. Подробно — /errors/ → раздел 5. - «WP перезаписал мой .htaccess». WordPress перегенерирует блок
# BEGIN WordPress … # END WordPressпри каждом сохранении настроек постоянных ссылок. Свои правила кладите выше или ниже этого блока — WP их не тронет. - Мультисайт (Multisite). WordPress Multisite генерирует другие блоки для подкаталогов (subdirectory) и поддоменов (subdomain) — не редактируйте их вручную, используйте панель Network Admin → Настройки → Постоянные ссылки.
- Разобрать чужой WP
.htaccessпострочно — инструмент «Объяснить .htaccess».
13. Чеклист: WP .htaccess за 5 минут
- Блок
# BEGIN WordPressна месте, ЧПУ работают? — раздел 1, /errors/ → ЧПУ wp-config.phpи.gitзакрыты (Require all denied)? — раздел 4, /security/xmlrpc.phpотключён или ограничен по IP? — раздел 5wp-login.phpпод IP-фильтром или HTTP Basic? — раздел 6, /htpasswd/- PHP в
wp-content/uploads/запрещён? — раздел 8 - Кэш статики и gzip настроены (и не конфликтуют с плагином кэша)? — раздел 9, /performance/
- Заголовки безопасности стоят (без агрессивного CSP, ломающего админку)? — раздел 10, /headers/
- Синтаксис
.htaccessпроверен линтером? — /check/, /audit/
14. Ссылки и инструменты
- Генератор .htaccess — собрать блоки чекбоксами (HTTPS, кэш, gzip, заголовки, защита).
- Безопасность сайта через .htaccess — полный гид: заголовки, закрытие файлов, IP, пароль, анти-бот.
- Ускорение сайта через .htaccess — кэш статики, gzip / Brotli, ETag, preload.
- Справочник HTTP-заголовков — разбор каждого заголовка безопасности, CORS, кэша.
- Генератор .htpasswd — bcrypt / APR1-MD5 / SHA / crypt для Basic Auth.
- Линтер .htaccess — найдёт ошибки синтаксиса, опасные директивы,
php_valueна FPM. - Аудит безопасности .htaccess — проверить файл на пробелы в защите.
- Конвертер 2.2↔2.4 —
Order/Allow/Deny↔Require. - Почему .htaccess не работает — 500 / 403 / 404, бесконечный редирект — симптом → причина → исправление.
- Объяснить .htaccess — разобрать чужой WP
.htaccessпострочно. - Рецепты .htaccess — готовые блоки под типовые задачи.
- Ограничение доступа по IP · Защита папки паролем · Справочник директив.
- .htaccess для других CMS и фреймворков — Laravel, Symfony, Joomla, Drupal, Bitrix, Yii, OpenCart, CodeIgniter…
- Готовые .htaccess под задачу — в т.ч. полный файл для блога на WordPress