301 редирект у .htaccess - це один рядок:
Redirect 301 /old-page https://example.com/new-page
Збережіть це у файлі .htaccess у вашому document root, і воно стане активним негайно. Apache читає файл на кожен запит, тож нема ні перезапуску, ні деплою. Директива походить з mod_alias, який присутній практично на кожній інсталяції Apache, і вона відправляє 301 Moved Permanently із заголовком Location. Це вся робота.
Майже все, що йде не так із редиректами Apache, трапляється вже після цього моменту: сягання за RewriteRule, коли достатньо Redirect, змішування двох модулів в одному файлі й отримання порядку, якого ніхто не очікував, або втрата рядка запиту по дорозі. Цей матеріал охоплює чотири правила, які варто запам'ятати, пастку з порядком виконання, через яку правильні на вигляд файли поводяться неправильно, і те, як перевірити редирект без брехні вашого браузера. Для ширшої картини того, де можуть жити редиректи, дивіться як перенаправити URL.
Один рядок, що охоплює більшість редиректів
Redirect приймає статус, шлях для збігу і ціль. Ціль може бути повним URL або шляхом на тому самому хості:
Redirect 301 /old-page /new-page
Redirect 301 /shop https://shop.example.com/
RedirectMatch 301 ^/blog/([0-9]{4})/(.*)$ /articles/$2
Перед використанням варто знати дві поведінки. По-перше, власні рекомендації Apache прямо кажуть, що це правильний інструмент: "Такий простий редирект одного URL або класу URL кудись в інше місце слід реалізовувати за допомогою цих директив, а не RewriteRule."
По-друге, і це дивує людей: "Пам'ятайте, що Redirect зберігає інформацію про шлях. Тобто редирект для URL /one також перенаправить усі URL під ним, такі як /one/two.html і /one/three/four.html." Якщо ви хочете лише точний шлях, RedirectMatch 301 ^/one$ фіксує його. Інакше ви щойно перенаправили цілісне піддерево, а це іноді саме те, чого ви хотіли, а іноді - дуже заплутаний ранок.
RedirectMatch - це regex-версія, і вона охоплює більшість того, для чого люди відкривають mod_rewrite. Захоплені групи потрапляють у $1, $2 і так далі, тож перейменування директорії чи зміна схеми URL на основі дати вирішуються одним рядком.
Коли вам справді потрібен RewriteRule
Сягайте за mod_rewrite, коли рішення залежить від чогось іншого, ніж шлях. Хост, рядок запиту, метод запиту, cookies і user agent - усе це видно RewriteCond і невидно Redirect:
RewriteEngine On
RewriteCond %{QUERY_STRING} (^|&)ref=oldpartner(&|$)
RewriteRule ^landing$ /partners/oldpartner? [R=301,L]
Є одна пастка в per-directory контексті, яка пояснює величезну частку скопійованих правил, що взагалі нічого не роблять. Apache відсікає префікс директорії до збігу, тож шаблон ніколи не бачить провідного слеша: "Видалений префікс завжди закінчується слешем, а це означає, що збіг відбувається з рядком, який ніколи не має провідного слеша. Тому шаблон з ^/ ніколи не збігається в per-directory контексті."
Саме тому RewriteRule ^/old$ /new [R=301] працює, коли хтось вставляє це у virtual host, і мовчки не працює у .htaccess. Приберіть слеш: ^old$. Коли ваша підстановка - відносний шлях, а rewrite живе в підкаталозі, вам також може знадобитися RewriteBase, щоб повідомити Apache, відносно чого рахувати шляхи.
Пастка порядку виконання
Це та пастка, яка коштує людям цілого дня. Позиція рядка у файлі не визначає, який модуль запускається першим.
Apache документує це прямо: "Якщо ви змішуєте Redirect і RewriteRule в одному контексті, знайте, що порядок їхнього виконання залежить від того, де вони з'являються. У контексті сервера/virtual-host mod_rewrite запускається першим; у per-directory контексті (.htaccess) першим запускається mod_alias."
Прочитайте це двічі, бо наслідок протиінтуїтивний. У файлі .htaccess Redirect в кінці файлу переможе RewriteRule на початку. Перенесіть ідентичні правила у virtual host - і переможець зміниться. Прапорець [L] вас теж не врятує: він означає останнє правило в цьому проході mod_rewrite, а не останнє правило у файлі, і він не має влади над іншим модулем.
Практичне правило, яке я дотримуюсь: один модуль на файл. Якщо проекту хоч десь потрібні умови, робіть усі його редиректи через mod_rewrite і видаляйте рядки Redirect. Саме змішані файли породжують баг-репорти типу "редирект працює на staging, але не на продакшені", бо два середовища ставлять правила в різні контексти.
Рядки запиту: збережені, замінені або стерті
Маркетингові посилання живуть і вмирають своїми рядками запиту, тож цю таблицю варто закріпити на видному місці. Усе тут - документована поведінка, а не фольклор.
| Що ви пишете | Оригінальний рядок запиту | Примітки |
|---|---|---|
Redirect 301 /a /b | Переноситься | mod_alias додає його за вас |
RedirectMatch 301 ^/a$ /b | Переноситься | Той самий модуль, та сама поведінка |
RewriteRule ^a$ /b [R=301] | Проходить незмінним | Задокументована поведінка за замовчуванням |
RewriteRule ^a$ /b?src=x [R=301] | Замінюється вашим | Ваші параметри перемагають |
RewriteRule ^a$ /b?src=x [R=301,QSA] | Поєднується з вашим | QSA додає оригінал |
RewriteRule ^a$ /b? [R=301] | Стирається | Самотній ? очищає його |
Формулювання Apache щодо поведінки за замовчуванням: "За замовчуванням рядок запиту передається без змін." А щодо прапорців, [QSA] "додає будь-який рядок запиту з оригінального URL запиту до будь-якого рядка запиту, створеного в цілі rewrite", тоді як [QSD] відкидає вхідний. Якщо ви робите редирект на абсолютний URI, рядок запиту йде разом, якщо ви не попросили [QSD].
Збій, якому це запобігає, тихий і дорогий. Правило, що замінює рядок запиту, вирізає utm_source і utm_campaign по дорозі, ваша аналітика приписує сесію прямому трафіку, і жодної помилки не виникає. Ніхто не помічає, доки хтось не запитає, чому весняна кампанія не отримала своєї заслуги. UTM-параметри не показуються в GA4 охоплює діагностику з боку аналітики.
Якщо ви ловите себе на тому, що підтримуєте десятки кампанійних редиректів у конфігураційному файлі сервера, - це сигнал, а не рутина. Правила на сервері потребують деплою, перегляду конфігурації Apache і когось із доступом до shell. Перенесіть посилання кампаній на короткі посилання, які можете редагувати самі, а .htaccess залишіть для структурних редиректів, у яких він справді хороший.
HTTPS і www за один перехід, а не за два
Найкопійованіший фрагмент коду в інтернеті робить це у двох блоках правил, а це означає, що відвідувач, який прийшов на http://example.com/page, отримує редирект двічі: раз - щоб додати TLS, раз - щоб додати www. Два переходи, два round trip, і трохи слабший сигнал на кожному.
Одне правило, дві умови, один перехід:
RewriteEngine On
RewriteCond %{HTTPS} !=on [OR]
RewriteCond %{HTTP_HOST} !^www\.example\.com$ [NC]
RewriteRule ^ https://www.example.com%{REQUEST_URI} [R=301,L]
За CDN чи балансувальником навантаження %{HTTPS} зазвичай off на origin, навіть коли відвідувач на HTTPS, бо TLS завершується вище за течією. Замість цього перевіряйте %{HTTP:X-Forwarded-Proto}:
RewriteCond %{HTTP:X-Forwarded-Proto} !https
Помилка тут - і ви будуєте нескінченний цикл редиректів: проксі відправляє HTTPS, origin думає, що це HTTP, робить редирект на HTTPS, і так по колу, доки браузер не здасться. Як виправити цикл редиректів розкриває діагностику цього за заголовками відповіді.
Чому воно не працює
У порядку, в якому я їх перевіряю:
AllowOverrideвиставлено вNone. Документація Apache озвучує поведінку за замовчуванням: "Це означає, що файли.htaccessповністю ігноруються, якщо ви явно не увімкнете їх для директорії." Перевірте це, поставивши навмисне сміття в перший рядок. Відсутність помилки 500 означає, що ваш файл узагалі не читається, і кожне правило в ньому - декорація.- Файл розміщений не там, де треба, або має неправильну назву. Він має бути саме
.htaccess, з провідною крапкою, у тій директорії, на яку відображається запит. Редактори, які "допомагають" зберегти його якhtaccess.txt, - постійна причина. - mod_rewrite не завантажений.
Redirectпрацює,RewriteRuleмовчки не працює, і люди годину шукають помилку у своєму regex. - Ваш браузер закешував старий 301. Chrome і Firefox обидва агресивно кешують постійні редиректи, у межах профілю браузера, тож фікс, який ви щойно задеплоїли, невидимий саме вам, а для всіх інших чудово працює. Під час розробки використовуйте
R=302і перемикайтеся наR=301, коли правило вже правильне. - Правило збігається з власною ціллю.
RewriteRule ^(.*)$ /index.php/$1без захисту - класика. Додайте умову, яка виключає ціль.
Перевіряйте через curl, а не браузер
Одна команда скаже вам статус, ціль і скільки переходів це зайняло:
curl -sIL https://example.com/old-page | grep -iE '^HTTP|^location'
Читайте вивід як послідовність. Два рядки HTTP/2 301 перед 200 означають два переходи, і кожен перехід - справжній round trip для справжнього відвідувача в мобільній мережі. Документація Google про редиректи трактує постійний редирект як найсильніший сигнал для консолідації URL, і дістатися туди за один крок строго краще, ніж за три. Наш перевіряч посилань друкує той самий ланцюжок у браузері, а 301 проти 302 редиректів охоплює, який статус відправляти, коли ви не впевнені.
Перевіряйте шляхи, які мають значення, а не лише той, що ви щойно написали: корінь, глибокий шлях, шлях із рядком запиту, і саму ціль. Останній варіант ловить цикли раніше за ваших відвідувачів.
Коли не варто використовувати .htaccess взагалі
Власна позиція Apache однозначна. "Якщо у вас є доступ до основного конфігураційного файлу сервера, вам слід розмістити всю конфігурацію там, а не у файлах .htaccess," бо парсинг на кожен запит коштує реальної роботи: "дозвіл на файли .htaccess спричиняє удар по продуктивності, незалежно від того, чи ви їх насправді використовуєте." На shared-хостингу у вас немає вибору. На сервері, який контролюєте ви, основна конфігурація - краще місце для всього структурного.
Є ще один аргумент тримати правила осторонь від файлу взагалі, і він не має нічого спільного з продуктивністю. Редиректи, що з'являються в друці, в QR-коді чи в чиїйсь презентації, мають переживати ваш веб-сервер, вашу міграцію CMS і, можливо, вашого хостинг-провайдера. Правило в .htaccess - це один неохайний деплой від зникнення, і ніхто не повідомляє про мертве надруковане посилання, доки кампанія не закінчиться. Структурним редиректам місце на сервері; кампанійним і друкованим посиланням - там, де ви можете редагувати їх за секунди й вимірювати без грепання логів доступу.
Читайте наріжну серію
Цей матеріал належить до кластера туторіалів. Для повної карти типи редиректів охоплює кожен код статусу і клієнтський метод, а як перенаправити URL охоплює шість місць, де може жити редирект.
Пов'язане в блозі
Поширені запитання
Як створити 301 редирект у .htaccess?
Додайте один рядок у файл .htaccess у корені вашого document root: Redirect 301 /old-page https://example.com/new-page. Apache читає .htaccess на кожен запит, тож редирект стає активним у момент збереження файлу. Без перезапуску, без деплою. Ця директива походить із mod_alias, який увімкнений практично на кожній інсталяції Apache.
Яка різниця між Redirect і RewriteRule?
Redirect і RedirectMatch походять з mod_alias і роблять одну річ: відправляють код статусу і заголовок Location. RewriteRule походить з mod_rewrite і може перевіряти хост, рядок запиту, cookies чи user agent перед тим, як прийняти рішення. Власна документація Apache каже, що для простого редиректу слід використовувати mod_alias, а не RewriteRule, і трактує mod_rewrite як останній засіб.
Чому мій редирект у .htaccess не працює?
П'ять причин охоплюють майже все: AllowOverride виставлено в None, тож файл повністю ігнорується; файл не в document root або має неправильну назву; mod_rewrite не завантажений; браузер закешував попередній 301 і більше не звертається до сервера; або правило збігається з власною ціллю і зациклюється. Перевіряйте через curl, а не браузер, бо закешований 301 змушує виправлене правило виглядати зламаним.
Чи переживає рядок запиту 301 редирект у .htaccess?
З Redirect і RedirectMatch - так, він переноситься автоматично. З RewriteRule відповідь залежить від підстановки: без знака питання в ній - оригінальний рядок запиту проходить далі, знак питання і власні параметри замінюють оригінал, самотній знак питання в кінці стирає його, а прапорець QSA поєднує обидва. Помилка тут мовчки викидає UTM-параметри.
Як перенаправити HTTP на HTTPS та non-www на www за один перехід?
Використайте одне правило з двома умовами, з'єднаними через OR, яке переписує на канонічну схему та хост за один крок. Два окремі блоки правил створюють два редиректи для кожного, хто заходить на http:// без www, а кожен додатковий перехід коштує затримки й розмиває сигнал. За проксі чи CDN перевіряйте %{HTTP:X-Forwarded-Proto} замість %{HTTPS}, інакше отримаєте цикл.
Чи сповільнює .htaccess сайт?
Трохи, і неминуче. Документація Apache каже про це прямо: дозвіл на файли .htaccess спричиняє удар по продуктивності незалежно від того, використовуєте ви їх чи ні, бо httpd шукає цей файл у кожній директорії на кожен запит. Якщо у вас є доступ до основної конфігурації сервера, ті самі правила краще розмістити там, завантажуючи їх один раз під час старту.
Спробуйте Elido
Вставте URL - отримайте коротке посилання
Без реєстрації. Посилання живе 30 днів. Зареєструйтесь, щоб зберегти назавжди.
Безкоштовно, без реєстрації · 2 на день