Як lowercase-редирект ламає індексацію URL з кирилицею та іншими не-ASCII символами
Марко Федоренко «Переадресовуй усі URL на нижній регістр» — типова порада з технічного SEO. Вона прибирає дублі на кшталт /Page/ і /page/ і для простих латинських адрес працює. Я перевірив її на кириличній адресі, і Googlebot за тиждень так і не дійшов до сторінки, хоча в браузері вона відкривалася без проблем.
Нижче розбираю механіку цієї петлі, показую, як налаштувати lowercase-редирект без неї, і як перевірити свій сайт. Повні дані тесту з логами сервера зібрано в окремій картці тесту.
Як не-ASCII символи потрапляють в адресу
Кирилиця, грузинська чи латиниця з діакритикою не можуть стояти в URL напряму. Браузер переводить кожен символ у байти UTF-8, а кожен байт записує як % і два hex-символи. Літера «т» стає %D1%82, а é стає %C3%A9.
Hex-символи A–F можна писати великими або малими літерами. За RFC 3986 записи %D1%82 і %d1%82 означають одне й те саме. Стандарт радить великі літери, а в розділі про нормалізацію прямо каже приводити до них інші записи.
Перший байт будь-якого не-ASCII символу в UTF-8 має код від C2 до F4. Тому в записі кожного такого символу є хоча б одна hex-літера. Те саме стосується закодованих знаків на кшталт коми %2C чи двокрапки %3A.
Як працює найпростіший lowercase-редирект
Найпростіша реалізація бере сирий рядок запиту й переводить його в нижній регістр. У nginx це змінна $request_uri, яка зберігає адресу саме в тому вигляді, як її надіслав клієнт. Якщо зменшений рядок відрізняється від початкового, правило відповідає 301.
Для латинської адреси без кодування все гаразд: /Page/ стає /page/. З не-ASCII адресами правило поводиться інакше. Ось що воно робить з трьома прикладами:
| Запит | Відповідь сервера | Що вийшло |
|---|---|---|
/%D1%82%D0%B5%D1%85… («технічний», стандартне кодування) | 301 на /%d1%82%d0%b5%d1%85… | Літери ті самі, змінився лише регістр hex |
/%D0%A2%D0%B5%D1%85… («Технічний», з великої літери) | 301 на /%d0%a2%d0%b5%d1%85… | Велика «Т» лишилася великою |
/caf%C3%A9/ | 301 на /caf%c3%a9/ | Літери ті самі, змінився лише регістр hex |
Таблиця показує дві проблеми одразу. Правило не зменшує кириличні літери, бо вони закодовані, тож своєї мети не досягає. Зате воно міняє регістр hex-символів і створює редирект там, де адреса вже була правильною.
Причинно-наслідковий ланцюжок
Сервер у цій історії лише відповідає редиректом. Петлю замикає краулер, який нормалізує адреси за RFC 3986 перед кожним запитом. Для Googlebot події йдуть так:
- Googlebot запитує стандартну адресу
/%D1%82…і отримує 301. - У заголовку
Locationстоїть адреса з малими hex/%d1%82…. - Перед наступним запитом Googlebot нормалізує її і знову отримує
/%D1%82…. - Сервер бачить ту саму адресу й знову відповідає 301.
- Після кількох спроб Googlebot зупиняється, так і не отримавши вмісту.
Браузер поводиться інакше. У моєму тесті Chrome узяв адресу з Location як є і не змінив регістр hex. Він зробив один редирект, отримав 200 і показав сторінку, тому людина проблеми не помічає.
Що показав тест
Я відтворив таке правило для однієї сторінки й тиждень збирав логи nginx. Адресу з малими hex я давав Google трьома шляхами: через URL Inspection, через окремий sitemap і через заголовок Location. Ось головні факти:
- Google запитав сторінку 36 разів, і всі 36 запитів ішли до форми з великими hex;
- у URL Inspection кожен прохід петлі складався з шести запитів окремо для мобільного й десктопного агента, а кожен візит звичайного Googlebot з трьох;
- форму з малими hex Google не запитав жодного разу, навіть коли брав адресу з sitemap;
- Chrome, ClaudeBot і QlyzeBot отримали сторінку з кодом 200.
Таблиця всіх запитів і приклади рядків з логів є в картці тесту.
Як я перевірив, що це справді Google
User-Agent легко підробити, тому IP-адреси я перевірив так, як радить Google. Зворотний DNS для кожної адреси повертає ім’я в домені googlebot.com, а прямий запит до цього імені повертає ту саму IP-адресу. Один запит «bingbot» не пройшов такої перевірки, тож я його не враховував.
Як налаштувати lowercase-редирект безпечно
Сам редирект на нижній регістр не шкідливий. Проблема в тому, що найпростіше правило працює із закодованим рядком. Безпечна реалізація спершу декодує шлях, потім зменшує літери й лише після цього кодує результат назад.
Ось ця логіка мовою JavaScript. Її легко перенести в серверне middleware на іншій мові:
const decoded = decodeURI(path); // "/Технічний-аудит/"
const lower = decoded.toLowerCase(); // "/технічний-аудит/"
if (lower !== decoded) {
redirect(301, encodeURI(lower)); // "/%D1%82%D0%B5…", великі hex
}
Функція encodeURI завжди повертає стандартну форму з великими hex-символами. Тому адреса, яка відрізняється лише регістром hex, не отримує редиректу, а адреса з великою кириличною літерою отримує правильний редирект на малу. Якщо в адресах сайту трапляються закодовані службові символи на кшталт %2F, цю логіку треба доповнити: decodeURI їх не декодує, і encodeURI закодує їхній % удруге.
Що звірити після налаштування
Саме правило ще не гарантує, що Googlebot отримає сторінку з першого запиту. Адреса має бути однаковою скрізь, де її бачить пошуковик. Варто звірити кілька речей:
canonical, sitemap і внутрішні посилання містять стандартну форму з великими hex;- адреса з великими hex відповідає 200 або веде на сторінку з 200 за один крок;
- правило не чіпає параметри запиту, якщо в них є регістрозалежні значення.
Так кожна сторінка має одну стандартну адресу, і Googlebot отримує її з першого запиту.
Як перевірити свій сайт
Перевірка займає кілька хвилин і не потребує доступу до сервера. Візьми сторінку з кирилицею, діакритикою чи закодованим знаком в адресі. Далі виконай такі кроки:
- Запроси її через
curl -sIу стандартному кодуванні з великими hex. - Подивись на код відповіді й заголовок
Location. - Якщо у відповідь приходить 301, а в
Locationз’явилися малі hex, сайт має цю проблему.
Наприклад, для моєї тестової сторінки команда curl -sI "https://marko-f.com/%D1%82%D0%B5%D1%85%D0%BD%D1%96%D1%87%D0%BD%D0%B8%D0%B9-%D0%B0%D1%83%D0%B4%D0%B8%D1%82/" повертає 301 і Location з малими hex. Підтвердити проблему допоможуть логи сервера. Якщо Googlebot кілька разів поспіль запитує ту саму адресу й щоразу отримує 301, це та сама петля.
Джерела
Механіка спирається на стандарт URI та документацію Google. Поведінку браузера й краулерів я брав з логів власного сервера. Ось першоджерела, на які посилається текст:
- RFC 3986: розділ 2.1 про percent-кодування й розділ 6.2.2.1 про нормалізацію регістру hex-символів;
- Google: переадресації та Google Search: як Google обробляє редиректи 301;
- Google: перевірка запитів від краулерів Google: зворотний і прямий DNS-запит;
- MDN: encodeURI: як JavaScript кодує адреси.
Дані тесту зібрано на сервері marko-f.com з 17 по 24 жовтня 2026 року.
Матеріали marko-f.com частіше показуватимуться вам у Google Пошуку.