Справочник

RewriteRule в .htaccess: как устроены правила mod_rewrite

RewriteRule меняет адрес запроса или отправляет переадресацию, если адрес подходит под шаблон. Перед правилом могут стоять условия RewriteCond. Ниже — как читать такие строки, что значат флаги в квадратных скобках и как не устроить петлю, из-за которой сайт отвечает ошибкой 500.

≈ 12 мин чтения
Содержание 17

Что сделать прямо сейчас

  1. Перед правкой сохраните копию файла .htaccess к себе на компьютер: если что-то пойдёт не так, её можно будет вернуть.
  2. Для простой переадресации со страницы на страницу правила не нужны — хватит строки Redirect.
  3. Над правилами должна стоять строка RewriteEngine On: без неё mod_rewrite выключен.
  4. Добавляйте правила по одному и после каждого открывайте сайт: так сразу видно, какое из них сломало страницу.
  5. Переадресацию сначала проверяйте с 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 — пример

Источники

Сверено 14 октября 2026 года.

Что почитать дальше