301 редирект через .htaccess: готовые правила

301 редирект — это ответ сервера, который говорит браузеру и поисковому роботу: страница переехала навсегда, вот её новый адрес. От остальных способов «перекинуть» посетителя он отличается тем, что переносит в индекс не только адрес, но и накопленный вес ссылок. Ниже — готовые правила для .htaccess под типовые задачи, их аналоги для nginx и разбор ошибок, из-за которых переезд стоит сайту трафика.

Как это работает

Сервер отвечает на запрос кодом 301 и заголовком Location с новым адресом. Браузер сразу уходит туда, обычно незаметно для посетителя, и кеширует этот переход. Поисковик поступает так же: заменяет в индексе старый URL новым и передаёт ему ссылочный вес.

Браузер или роботGET /old-page/запросСервер301 Moved PermanentlyLocation: /new-page/правило из .htaccessпереходНовый адрес200 OK, страница открытаЧто важно для поиска301 говорит «адрес сменился навсегда»: поисковик переносит страницу в индексе вместе с накопленным весом ссылок.302 означает «временно» — старый адрес остаётся в индексе, и вес никуда не переходит.
Цепочка запроса: сервер отвечает 301 и передаёт новый адрес

Разница между кодами важна и стоит денег:

Код Что означает Когда применять
301 Переехало навсегда Смена домена, адреса страницы, склейка зеркал, переход на HTTPS
302 Временно Акция на пару недель, техработы, A/B-тест
307 Временно, метод запроса сохраняется То же, но для POST-запросов
308 Навсегда, метод сохраняется Редкий случай: переезд API, где важен POST
410 Удалено навсегда Страницы больше нет и замены ей нет

Путать 301 и 302 — самая дорогая ошибка в этом списке: при 302 поисковик оставляет в индексе старый адрес и вес на новый не передаёт.

Правила для .htaccess

Все примеры рассчитаны на Apache с включённым mod_rewrite. Блок правил ставится в начало файла .htaccess в корне сайта — до правил CMS, иначе WordPress перехватит запрос раньше.

RewriteEngine On
RewriteBase /

Одна страница на другую

# простой вариант
Redirect 301 /old-page/ https://site.com/new-page/

# тот же результат через mod_rewrite, если остальные правила тоже на нём
RewriteRule ^old-page/?$ https://site.com/new-page/ [R=301,L]

Склейка зеркал: с www на без www

RewriteCond %{HTTP_HOST} ^www.(.+)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]

Обратный случай, когда главным зеркалом выбран домен с www:

RewriteCond %{HTTP_HOST} !^www. [NC]
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}/$1 [R=301,L]

Переход на HTTPS

RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]

За Cloudflare или другим прокси условие %{HTTPS} не сработает — до сервера запрос доходит уже по HTTP. Там проверяют заголовок:

RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]

HTTPS и без www одним правилом

Главный приём этого раздела: не ставить два правила подряд, иначе получится цепочка из двух переходов.

RewriteCond %{HTTPS} !=on [OR]
RewriteCond %{HTTP_HOST} ^www.(.+)$ [NC]
RewriteRule ^(.*)$ https://site.com/$1 [R=301,L]

Слеш на конце адреса

# добавить слеш
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !.[a-zA-Z0-9]{1,5}$
RewriteCond %{REQUEST_URI} !/$
RewriteRule ^(.*)$ /$1/ [R=301,L]

# убрать слеш
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [R=301,L]

Условия с !-f и !-d здесь не формальность: без них правило начнёт переписывать адреса картинок и существующих папок.

Переезд на новый домен

# с сохранением адресов страниц — так и нужно делать
RewriteCond %{HTTP_HOST} ^(www.)?old-site.com$ [NC]
RewriteRule ^(.*)$ https://new-site.com/$1 [R=301,L]

# всё на главную — только если структура нового сайта совсем другая
RewriteRule ^(.*)$ https://new-site.com/ [R=301,L]

Второй вариант поисковики часто считают «мягкой 404» и вес не передают. Переносите адрес в адрес везде, где это возможно, а на главную отправляйте только то, чему замены нет.

Раздел на раздел и адреса с параметрами

# /blog/статья/ → /news/статья/
RewriteRule ^blog/(.*)$ /news/$1 [R=301,L]

# ?id=12 → /catalog/sofa/
RewriteCond %{QUERY_STRING} (^|&)id=12(&|$)
RewriteRule ^index.php$ /catalog/sofa/? [R=301,L]

Знак вопроса в конце цели отбрасывает исходную строку параметров — без него она приклеится к новому адресу.

То же самое на nginx

У nginx нет .htaccess: правила живут в конфиге сервера и применяются после nginx -t и перезагрузки.

server {
    listen 80;
    server_name www.site.com site.com;
    return 301 https://site.com$request_uri;
}

# одна страница на другую
location = /old-page/ {
    return 301 https://site.com/new-page/;
}

# раздел на раздел
rewrite ^/blog/(.*)$ /news/$1 permanent;

Конструкция return 301 быстрее, чем rewrite, и читается однозначно, поэтому для простых случаев берут именно её.

Частые ошибки

ТАК БЫВАЕТ: ЧЕТЫРЕ ПЕРЕХОДА ВМЕСТО ОДНОГОhttp://www.site.comhttp://site.comhttps://site.comhttps://site.com/page/Каждый шаг — отдельный запрос: дольше загрузка, часть веса теряется, робот тратит лимит обходаКАК НАДО: ОДНО ПРАВИЛО, ОДИН ПЕРЕХОДhttp://www.site.comодин 301https://site.com/page/Проверяется одной командой: curl -sIL https://site.com/page/ — в ответе должен быть ровно один 301
Цепочка из нескольких переходов и то, как должно быть
  • Цепочка редиректов. www → без www → https → слеш: четыре запроса вместо одного. Собирайте условия в одно правило.
  • Цикл. Правило отправляет страницу само на себя, браузер показывает ERR_TOO_MANY_REDIRECTS. Обычно причина — редирект на HTTPS за прокси по %{HTTPS}.
  • 302 вместо 301. Переезд сделан, а вес остался на старом адресе.
  • Всё на главную. Массовый редирект сотен страниц в корень поисковик считает подменой 404.
  • Правила после правил CMS. В .htaccess WordPress перехватит запрос первым, и ваше правило не сработает: ставьте свой блок выше.
  • Редирект вместо canonical. Если обе страницы нужны людям, а дублируется только содержимое, ставят rel="canonical", а не 301.
  • Забытые внутренние ссылки. После переезда ссылки внутри сайта должны вести на новый адрес напрямую, иначе каждый переход посетителя идёт через редирект.

Как проверить

Быстрее всего — командой в терминале. Ключ -I запрашивает только заголовки, -L идёт по цепочке до конца:

curl -sIL https://site.com/old-page/ | grep -E "HTTP/|Location"

Правильный ответ выглядит так: один HTTP/1.1 301, один Location и затем HTTP/2 200. Два и больше 301 подряд — это цепочка, её нужно схлопнуть. В Search Console тот же результат виден в отчёте «Индексирование страниц», а в браузере — во вкладке Network, если включить «Preserve log».

После массового переезда проверьте выборку из двух-трёх десятков адресов: главную, категории, карточки, страницы с параметрами и адреса из топа поисковой выдачи.

Коротко о главном

301 — для постоянного переезда, 302 — для временного, 410 — для того, чего больше нет. Правило пишется одно и ведёт сразу на конечный адрес, без промежуточных шагов. Проверять нужно всегда — curl -sIL отвечает на вопрос за секунду.

Если переезд большой — смена домена, объединение сайтов, переход на HTTPS с перестройкой адресов — напишите нам: составим карту соответствий и перенесём так, чтобы трафик остался на месте.