RewriteRule в .htaccess: как устроены правила mod_rewrite
RewriteRule меняет адрес запроса или отправляет переадресацию, если адрес подходит под шаблон. Перед правилом могут стоять условия RewriteCond. Ниже — как читать такие строки, что значат флаги в квадратных скобках и как не устроить петлю, из-за которой сайт отвечает ошибкой 500.
Содержание 17
- Что сделать прямо сейчас
- Как устроено правило
- Какой путь видит правило
- Как читать шаблон
- Переменные в условиях
- Флаги
- Переадресация: сначала 302, потом 301
- Параметры в адресе
- Все адреса в index.php
- WordPress: свои правила — вне блока WordPress
- Косая черта в конце адреса
- Петля и ошибка 500
- Правило не работает
- Журнал mod_rewrite на своём VPS
- Ошибки и как их исправить
- Источники
- Что почитать дальше
Что сделать прямо сейчас
- Перед правкой сохраните копию файла .htaccess к себе на компьютер: если что-то пойдёт не так, её можно будет вернуть.
- Для простой переадресации со страницы на страницу правила не нужны — хватит строки Redirect.
- Над правилами должна стоять строка
RewriteEngine On: без неё mod_rewrite выключен. - Добавляйте правила по одному и после каждого открывайте сайт: так сразу видно, какое из них сломало страницу.
- Переадресацию сначала проверяйте с R=302 — почему.
Как устроено правило
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC]
RewriteRule ^(.*)$ https://example.com/$1 [L,R=301]RewriteEngine Onвключает mod_rewrite для этого файла.RewriteCond— условие: что проверить (здесь имя сайта из переменной %{HTTP_HOST}), с каким шаблоном сравнить и флаги. NC — без учёта больших и маленьких букв.RewriteRule— само правило: шаблон пути, новый адрес и флаги. Скобки в шаблоне запоминают часть пути, и $1 подставляет её в новый адрес.- Флаги
[L,R=301]— отправить переадресацию с кодом 301 и дальше правила не проверять.
Условия относятся к одному правилу — тому, что стоит сразу под ними. Правило сработает, только если выполнены все его условия; флаг [OR] у условия меняет «и» на «или».
Какой путь видит правило
В .htaccess шаблон правила сравнивается с путём без домена, параметров и косой черты в начале: для адреса https://example.com/blog/post/ правило видит blog/post/, поэтому шаблон пишут как ^blog/, а не ^/blog/.
Если .htaccess лежит во вложенной папке, отрезается и её имя: для файла в папке blog тот же адрес выглядит как post/. Имя сайта и параметры после «?» шаблон не видит — их проверяют условием RewriteCond с %{HTTP_HOST} или %{QUERY_STRING}.
Новый адрес в правиле начинайте с косой черты (/index.php) или пишите целиком, с https://: так он не зависит от папки, где лежит .htaccess.
Как читать шаблон
Шаблоны в RewriteRule и RewriteCond — регулярные выражения. Самые нужные знаки:
| Знак | Что значит | Пример |
|---|---|---|
^ | начало строки | ^blog/ — путь начинается с blog/ |
$ | конец строки | \.php$ — путь кончается на .php |
. | любой один символ | c.t — cat, cut и другие |
\. | сама точка | index\.php |
+ | предыдущий знак один раз или больше | [0-9]+ — одна цифра или больше |
* | предыдущий знак любое число раз, в том числе ни разу | .* — что угодно, даже пустая строка |
? | предыдущего знака может не быть | pages? — page и pages |
( ) | группа: запоминает часть, её подставляют как $1, $2 | ^blog/(.+)$ |
[ ] | один символ из перечисленных | c[uoa]t — cut, cot, cat |
[^ ] | любой символ, кроме перечисленных | [^/]+ — часть пути до косой черты |
! | перед шаблоном: строка не должна подходить | !^admin/ |
$1 и $2 берут части из шаблона самого правила, %1 и %2 — из последнего сработавшего условия RewriteCond.
Переменные в условиях
| Переменная | Что в ней |
|---|---|
%{HTTP_HOST} | имя сайта из запроса, например www.example.com |
%{REQUEST_URI} | путь с косой чертой в начале, без параметров: /blog/post/ |
%{QUERY_STRING} | параметры после «?»: id=5&sort=price |
%{HTTPS} | on, если запрос пришёл по HTTPS, иначе off; на хостинге бывает off и на https:// — почему |
%{REQUEST_FILENAME} | полный путь к файлу на диске, который соответствует адресу |
%{HTTP_USER_AGENT} | название программы посетителя: браузера, бота, curl |
Перед шаблоном условия можно поставить знак = — тогда строка сравнивается целиком, без регулярного выражения: %{HTTPS} !=on значит «HTTPS не равно on». Проверки -f и -d узнают, есть ли на диске такой файл или папка.
Флаги
| Флаг | Что делает |
|---|---|
L | дальше правила не проверять; в .htaccess после замены адреса правила проверяются заново — почему бывает петля |
END | остановить обработку совсем, без нового прохода по правилам |
R=301 | отправить браузеру переадресацию с кодом 301; R без числа — 302; ставят вместе с L |
NC | не различать большие и маленькие буквы |
OR | у условия: достаточно этого или следующего условия |
QSA | добавить старые параметры к новым |
QSD | убрать старые параметры |
F | ответить 403 Forbidden |
G | ответить 410 Gone |
Флаги пишут в квадратных скобках через запятую: [L,R=301].
Если адрес менять не нужно, а нужен только флаг, вместо нового адреса ставят дефис. Правило ниже отвечает 403 программам, в названии которых есть BadBot:
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} BadBot [NC]
RewriteRule ^ - [F]Тот же запрет без mod_rewrite — в статье про запрет доступа.
Переадресация: сначала 302, потом 301
Браузер запоминает ответ 301 и потом сам уходит по старой переадресации, даже если правило уже исправлено. Поэтому документация Apache советует проверять правило с R=302, а когда всё работает — заменить на R=301. Проверять удобнее через curl: как это сделать.
Параметры в адресе
Параметры после «?» переходят в новый адрес без изменений. Если в новом адресе есть свой знак «?», старые параметры заменятся новыми. Флаг QSA добавит старые параметры после новых, флаг QSD уберёт их совсем; убрать их можно и знаком «?» в конце нового адреса.
RewriteEngine On
RewriteRule ^catalog/([0-9]+)/$ /catalog.php?id=$1 [QSA,END]Адрес /catalog/15/?sort=price откроет /catalog.php?id=15&sort=price, а в строке браузера останется /catalog/15/?sort=price: без флага R адрес меняется только внутри сервера.
Все адреса в index.php
Многие движки сайтов устроены так: любой адрес, которого нет на диске, открывает index.php, а он сам решает, что показать.
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ /index.php [END]Условия пропускают настоящие файлы и папки: стили, скрипты и картинки отдаются как есть. Адрес в браузере не меняется. Флаг END не даёт правилу сработать второй раз на /index.php.
То же самое делает одна строка — документация Apache называет этот способ проще и эффективнее, чем mod_rewrite:
FallbackResource /index.phpНа VPS с Ubuntu модуль mod_dir, где живёт эта строка, включён сразу после установки Apache. Если после неё сайт отвечает ошибкой 500, верните правило выше. Для сайта в папке пишите путь к его index.php: FallbackResource /blog/index.php.
WordPress: свои правила — вне блока WordPress
WordPress хранит свои правила в .htaccess между строками # BEGIN WordPress и # END WordPress и перезаписывает этот блок целиком, поэтому правки внутри него могут пропасть. Свои правила ставьте выше строки # BEGIN WordPress или ниже # END WordPress.
Правила выполняются сверху вниз, и сработавшее правило с флагом L или END останавливает следующие. Поэтому переадресации ставьте выше блока WordPress.
Косая черта в конце адреса
Правило убирает косую черту в конце: /contacts/ уйдёт на /contacts.
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]Первое условие не трогает настоящие папки, второе запоминает путь без последней косой черты — его подставляет %1. К настоящим папкам Apache сам добавляет косую черту в конце: за это отвечает настройка DirectorySlash, она включена по умолчанию.
Если косую черту в конце добавляет сам движок сайта, такое правило может устроить петлю: сначала посмотрите настройки адресов в движке. Правило, которое, наоборот, добавляет косую черту, есть в справке Спринтхоста — ссылка в источниках.
Петля и ошибка 500
В .htaccess после замены адреса Apache проверяет правила ещё раз — уже с новым адресом. Если правило снова срабатывает, круг повторяется. После 10 повторов Apache прекращает попытки и отвечает ошибкой 500, а в журнал ошибок пишет AH00124 Request exceeded the limit of 10 internal redirects….
Петлю убирает флаг END вместо L — так советует документация Apache — или условие, которое не пускает к правилу уже изменённый адрес, например RewriteCond %{REQUEST_FILENAME} !-f. Предел в 10 повторов задаётся в настройках сервера, в .htaccess его не поменять — и не нужно: петлю это не уберёт.
Правило не работает
- Нет строки
RewriteEngine Onнад правилами. - Шаблон начинается с косой черты: в .htaccess пишите
^blog/, а не^/blog/. - Во вложенной папке есть свой .htaccess со строками mod_rewrite — правила из верхней папки для неё не работают. Добавьте во вложенный файл строку
RewriteOptions Inherit: сначала выполнятся его правила, затем правила верхней папки. - Раньше сработало другое правило с флагом L или END.
- Браузер запомнил старую переадресацию 301 — проверяйте через curl или в окне инкогнито.
- На VPS не разрешено читать .htaccess — как разрешить .htaccess.
- У Спринтхоста .htaccess действует и на поддомены: если поддомен из-за правил сайта отвечает ошибкой 500, Спринтхост советует положить в папку поддомена .htaccess со строкой
RewriteEngine off.
Журнал mod_rewrite на своём VPS
Подробный журнал покажет, как Apache проходит каждое правило. Команды вводятся на сервере: подключитесь к нему по SSH (как подключиться) и набирайте их в том же окне. Откройте файл сайта:
sudo nano /etc/apache2/sites-available/example.com.confВместо example.com.conf — файл вашего сайта: список покажет ls /etc/apache2/sites-enabled/. Внутри блока <VirtualHost …> добавьте строку:
LogLevel alert rewrite:trace3Сохраните файл — Ctrl+O, Enter, затем Ctrl+X — и проверьте настройки: sudo apache2ctl configtest. В конце ответа должно быть Syntax OK. Тогда примените их: sudo systemctl restart apache2.
Если вместо Syntax OK пришла ошибка, Apache назовёт файл и номер строки: исправьте её и проверьте снова. Пока проверка не прошла, перезапуск не делайте.
Откройте страницу с правилом и посмотрите записи mod_rewrite — они помечены словом rewrite:
sudo grep -F '[rewrite:' /var/log/apache2/error.log | tail -n 30Если у сайта свой журнал ошибок — строка ErrorLog в том же файле, — смотрите в нём. Пока строка LogLevel стоит, в журнал попадают записи mod_rewrite и только самые серьёзные ошибки остальных модулей. Подробный журнал заметно замедляет сервер: после проверки уберите строку, снова проверьте настройки и перезапустите Apache. В .htaccess строку LogLevel не поставить — только в настройки сервера или сайта.
Ошибки и как их исправить
| Что видите | Что делать |
|---|---|
| ошибка 500 сразу после сохранения | опечатка в правиле или выключен mod_rewrite; на VPS включите его: sudo a2enmod rewrite и sudo systemctl restart apache2 — разбор |
| ошибка 500, в журнале AH00124 | петля: поставьте END вместо L или добавьте условие |
| ответ 403, в журнале AH00670 | выключен FollowSymLinks — например, строка Options без знака заменила весь набор; без него mod_rewrite в .htaccess не работает: пишите Options со знаком, например Options -Indexes |
| правило молчит, ошибок нет | разрешите .htaccess или пройдите список причин |
| ERR_TOO_MANY_REDIRECTS | правило переадресует на адрес, который снова под него подходит — разбор |
| после правила для index.php пропали стили и картинки | добавьте условия !-f и !-d — пример |
Источники
- Документация Apache: RewriteRule — шаблон, новый адрес и флаги; дефис вместо адреса; шаблон не видит имя сайта и параметры; параметры по умолчанию переходят без изменений, «?» в конце их убирает.
- Документация Apache: RewriteCond — переменные HTTP_HOST, REQUEST_URI, QUERY_STRING, HTTPS, REQUEST_FILENAME, HTTP_USER_AGENT; проверки -f и -d, сравнение со знаком =, флаги NC и OR, ссылки %1.
- Документация Apache: введение в mod_rewrite — знаки регулярных выражений, ссылки $1 и %1.
- Документация Apache: флаги RewriteRule — L, END, R, NC, QSA, QSD, F и G; R без числа даёт 302 и ставится вместе с L.
- Документация Apache: mod_rewrite в .htaccess — нужны AllowOverride FileInfo и FollowSymLinks; путь без косой черты в начале; RewriteBase; петли и флаг END; RewriteOptions Inherit; кэш браузера для 301.
- Документация Apache: все адреса в один скрипт — правило с проверками -f и -d; FallbackResource делает то же проще и эффективнее.
- Документация Apache: FallbackResource — разрешена в .htaccess при AllowOverride Indexes; для сайта в папке — путь вида /blog/index.php.
- Документация Apache: косая черта в конце — правило, которое убирает косую черту у адресов, не являющихся папками.
- Документация Apache: DirectorySlash — по умолчанию включена: к адресам папок Apache сам добавляет косую черту.
- Документация Apache: журнал mod_rewrite — строка LogLevel с rewrite:trace, отбор записей по метке rewrite; высокие уровни сильно замедляют сервер.
- Документация Apache: LogLevel — задаётся в настройках сервера, сайта и папки, но не в .htaccess.
- Документация Apache: LimitInternalRecursion — по умолчанию 10; задаётся только в настройках сервера и сайта.
- Исходный код Apache 2.4.58: mod_rewrite.c — без FollowSymLinks и SymLinksIfOwnerMatch mod_rewrite в .htaccess отвечает 403 и пишет в журнал AH00670.
- Исходный код WordPress 7.1.3: misc.php — блок между # BEGIN WordPress и # END WordPress перезаписывается целиком.
- Спринтхост: файл .htaccess — правило с флагом F по названию программы, строка RewriteEngine off для поддомена, правила для косой черты в конце.
Сверено 14 октября 2026 года.
Что почитать дальше
- Переадресация 301 в .htaccessготовые строки для страницы, раздела и сайта.
- Переадресация на HTTPS через .htaccessусловие для своего хостинга.
- Переадресация с www на адрес без wwwправило для главного адреса.
- Почему не работает .htaccessошибки и сообщения в журнале.
- try_files в nginxкак то же самое делают в nginx.