Редиректы в .htaccess — один из самых частых сценариев настройки веб-сервера Apache. Смена домена, переход на HTTPS, изменение структуры URL, склейка www — во всех этих случаях нужны корректные правила перенаправления. В этой статье собраны готовые примеры для типичных и нестандартных ситуаций. Перед внедрением правил рекомендуется проверить цепочки редиректов через инструмент проверки редиректов reChecker.
Базовые директивы редиректов
Apache поддерживает несколько способов задания редиректов. Выбор зависит от сложности условия и необходимости использования регулярных выражений.
Redirect vs RewriteRule
| Директива | Модуль | Синтаксис | Регулярные выражения |
|---|---|---|---|
Redirect | mod_alias | Простой путь | Нет |
RedirectMatch | mod_alias | Regex | Да |
RewriteRule | mod_rewrite | Regex | Да |
Директива Redirect проще в использовании, но не поддерживает условия. Для сложной логики используется mod_rewrite. Генерировать готовые правила можно в Генераторе .htaccess.
Простой Redirect
# 301 — постоянный редирект (передаёт ссылочный вес)
Redirect 301 /old-page.html /new-page.html
Redirect 301 /category/old-name /category/new-name
# 302 — временный редирект
Redirect 302 /maintenance /coming-soon
# 307 — временный с сохранением метода (POST остаётся POST)
Redirect 307 /api/submit /api/v2/submit
# 308 — постоянный с сохранением метода
Redirect 308 /old-api /new-api
Важно: при использовании Redirect путь в первом аргументе интерпретируется как префикс. Запрос /old-page.html?id=1 перенаправится на /new-page.html?id=1 — query string сохраняется автоматически.
RedirectMatch с регулярными выражениями
Когда нужны паттерны, используйте RedirectMatch. Для отладки regex полезен Regex Tester на reChecker.
# Редирект всех .html на версию без расширения
RedirectMatch 301 ^/(.+)\.html$ /$1
# Редирект старых ID страниц
RedirectMatch 301 ^/product/([0-9]+)\.php$ /products/$1
# Редирект датированных URL
RedirectMatch 301 ^/blog/([0-9]{4})/([0-9]{2})/(.+)\.html$ /articles/$3
mod_rewrite: полный контроль
mod_rewrite даёт максимальную гибкость: условия, захват групп, проверка переменных окружения.
Включение движка
RewriteEngine On
RewriteBase /
RewriteBase задаёт базовый путь для подстановок. На корне сайта обычно /.
Флаги RewriteRule
| Флаг | Назначение |
|---|---|
R=301 | Код ответа 301 |
R=302 | Код ответа 302 |
L | Last — остановить обработку правил |
NC | No Case — игнорировать регистр |
QSA | Query String Append — добавить исходный query string |
NE | No Escape — не экранировать специальные символы в подстановке |
OR | Или — объединить условия (RewriteCond) |
Базовые примеры RewriteRule
RewriteEngine On
# Одна страница на другую
RewriteRule ^old-page$ /new-page [R=301,L]
# С сохранением query string
RewriteRule ^search\.php$ /search [R=301,L,QSA]
# Игнорирование регистра
RewriteRule ^About$ /about [R=301,L,NC]
# Захват группы и подстановка
RewriteRule ^blog/post-([0-9]+)\.html$ /articles/$1 [R=301,L]
Редирект HTTP → HTTPS
Обязательный шаг после установки SSL. Весь HTTP-трафик должен перенаправляться на HTTPS.
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
Вариант с явным указанием домена:
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://example.com/$1 [R=301,L]
Через Redirect (проще, но без условий):
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
Склейка www и non-www
Две версии сайта создают дублирование контента. Выберите одну каноническую и настройте редирект.
С www на без www
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]
С без www на www
RewriteEngine On
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{HTTP_HOST} ^(.+)$ [NC]
RewriteRule ^(.*)$ https://www.%1/$1 [R=301,L]
Комбинированный: HTTP → HTTPS + www
RewriteEngine On
# Сначала на HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
# Затем на www
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{HTTP_HOST} ^(.+)$ [NC]
RewriteRule ^(.*)$ https://www.%1/$1 [R=301,L]
Подробнее о выборе канонического домена и SEO-аспектах — в руководстве по оптимизации редиректов.
Trailing slash: с косой чертой или без
Единообразие URL влияет на индексацию. Выберите один формат.
Добавление trailing slash
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ /$1/ [R=301,L]
Удаление trailing slash
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [R=301,L]
Условие !-d предотвращает редирект для реальных директорий (иначе /blog/ перестанет открывать папку).
Смена домена
При переносе сайта на новый домен все старые URL должны вести на соответствующие страницы нового домена.
RewriteEngine On
RewriteCond %{HTTP_HOST} ^old-domain\.com$ [OR]
RewriteCond %{HTTP_HOST} ^www\.old-domain\.com$
RewriteRule ^(.*)$ https://new-domain.com/$1 [R=301,L]
Сохранение структуры путей:
RewriteRule ^(.*)$ https://new-domain.com/$1 [R=301,L,QSA]
QSA сохраняет параметры: old-domain.com/page?utm_source=google → new-domain.com/page?utm_source=google.
Редиректы по регулярным выражениям
Удаление расширения .html
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)\.html$ /$1 [R=301,L]
Добавление .html (обратный редирект)
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^(.+)$ $1.html [R=301,L]
Редирект старых ID на новый формат
# /item.php?id=12345 → /items/12345
RewriteCond %{QUERY_STRING} ^id=([0-9]+)$
RewriteRule ^item\.php$ /items/%1? [R=301,L]
Символ ? в конце подстановки убирает исходный query string. Без него получится /items/12345?id=12345.
Редирект по языку в URL
# /en/about → /about (удаление префикса языка)
RewriteRule ^en/(.*)$ /$1 [R=301,L]
# Или наоборот: /about → /ru/about
RewriteCond %{HTTP:Accept-Language} ^ru [NC]
RewriteRule ^(.*)$ /ru/$1 [R=302,L]
Редирект с условиями
Редирект только для определённого User-Agent
RewriteCond %{HTTP_USER_AGENT} ^Googlebot [NC]
RewriteRule ^old-sitemap\.xml$ /new-sitemap.xml [R=301,L]
Редирект по IP (например, для бета-тестеров)
RewriteCond %{REMOTE_ADDR} ^192\.168\.1\.(100|101|102)$
RewriteRule ^(.*)$ /beta/$1 [R=302,L]
Редирект мобильных на отдельный поддомен
RewriteCond %{HTTP_USER_AGENT} (android|blackberry|iphone|ipad|ipod) [NC]
RewriteCond %{HTTP_HOST} !^m\.example\.com$
RewriteRule ^(.*)$ https://m.example.com/$1 [R=302,L]
Редирект целых разделов
Смена структуры каталогов
# /shop/category/old-name/ → /catalog/new-name/
RewriteRule ^shop/category/old-name/(.*)$ /catalog/new-name/$1 [R=301,L]
# Все страницы раздела
RewriteRule ^old-section/(.*)$ /new-section/$1 [R=301,L]
Редирект с изменением параметров
# /page?sort=old → /page?order=new
RewriteCond %{QUERY_STRING} sort=old
RewriteRule ^page$ /page?order=new [R=301,L,QSD]
QSD (Query String Discard) удаляет исходный query string перед добавлением нового.
Редирект ошибок и специальных случаев
Редирект 404 на главную
ErrorDocument 404 /index.html
Или на кастомную страницу:
ErrorDocument 404 https://example.com/404
ErrorDocument 500 https://example.com/500
Редирект с сохранением пути (для SPA)
В одностраничных приложениях все неизвестные пути часто ведут на index.html:
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
Здесь [L] без R — внутренняя перезапись, без HTTP-редиректа.
Порядок правил и производительность
Правила обрабатываются сверху вниз. Рекомендации:
- Сначала специфичные правила — одиночные страницы, точные пути.
- Затем общие — домен, HTTPS, www, trailing slash.
- Используйте
L— останавливайте обработку после срабатывания. - Избегайте циклических редиректов — проверяйте условия (например,
RewriteCond %{HTTPS} offперед редиректом на HTTPS).
Типичная структура:
RewriteEngine On
RewriteBase /
# 1. Специфичные страницы
RewriteRule ^old-contact$ /contact [R=301,L]
RewriteRule ^legacy-page\.php$ /new-page [R=301,L,QSA]
# 2. HTTP → HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
# 3. www / non-www
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}/$1 [R=301,L]
Проверка и отладка
После настройки редиректов проверьте:
- Цепочки редиректов — не должно быть двойных или циклических перенаправлений. Используйте проверку редиректов reChecker.
- Код ответа — 301 для постоянных, 302 для временных.
- Сохранение параметров — при необходимости добавляйте
QSA. - Кэширование — браузеры кэшируют 301, тестируйте в режиме инкогнито или с очищенным кэшем.
Редирект по коду ответа
Иногда нужно перенаправлять только при определённом статусе. Через ErrorDocument:
ErrorDocument 404 https://example.com/404
ErrorDocument 403 https://example.com/access-denied
ErrorDocument 500 https://example.com/error
Редирект 404 на релевантную страницу (например, поиск по slug):
ErrorDocument 404 /index.php?page=404
Редирект с учётом query string
По умолчанию RewriteRule не передаёт query string. Добавьте QSA (Query String Append):
RewriteRule ^old-path$ /new-path [R=301,L,QSA]
Запрос /old-path?utm_source=google станет /new-path?utm_source=google.
Удаление query string при редиректе — добавьте ? в конец подстановки:
RewriteRule ^old-path$ /new-path? [R=301,L]
Редирект мобильных устройств
Отдельный поддомен для мобильной версии:
RewriteCond %{HTTP_USER_AGENT} (android|blackberry|iphone|ipad|ipod|mobile) [NC]
RewriteCond %{HTTP_HOST} !^m\.example\.com$
RewriteRule ^(.*)$ https://m.example.com/$1 [R=302,L]
302 — временный, чтобы поисковики не переносили весь вес на m-версию. Для мобильного-first лучше не делать отдельный поддомен.
Редирект по геолокации
Требует mod_geoip или mod_geoip2:
RewriteCond %{ENV:GEOIP_COUNTRY_CODE} ^RU$
RewriteRule ^(.*)$ https://ru.example.com/$1 [R=302,L]
Типичные ошибки
- Циклический редирект — правило перенаправляет на URL, который снова попадает под то же правило. Проверяйте условия (HTTPS, www).
- Потеря query string — добавьте
QSAили явно передайте$QUERY_STRING. - Двойной редирект — HTTP→HTTPS и www→non-www в неправильном порядке. Сначала HTTPS, затем канонический домен.
- Ошибка 500 — синтаксис в
RewriteRule, неверный путь к файлу, отсутствиеRewriteEngine On.
Полный обзор возможностей .htaccess — в руководстве по .htaccess.