Skip to content
Назад к статьям
Руководство5 мин чтения

Как исправить 404 на /cdn-cgi/l/email-protection в Search Console (обфускация email в Cloudflare)

Две ошибки в Search Console, которых мой код не создавал: обфускация email в Cloudflare порождает 404, а запись www всё ещё ведёт на парковку Namecheap.

CloudflareSEOSearch ConsoleDNSAstro
Заголовок «Errors your build can’t see» рядом с карточкой в стиле Search Console «Why pages aren’t indexed»: зачёркнутый 404 на /cdn-cgi/l/email-protection, исправленный маркерами email_off, и зачёркнутый 525 на www.pavelsmolin.com, исправленный редиректом 301 по http.host; внизу — build clean, edge 2 errors, fixed 2 / 2

Этот сайт статический. Его собирает Astro, отдаёт Cloudflare Pages, а CI проверяет каждый pull request. Сборка ни разу не выдала битую ссылку. И всё же Search Console нашёл на сайте две ошибки: Not found (404) и Server error (5xx).

Ни одна из них не пришла из репозитория. Обе — из настроек Cloudflare, который стоит перед сайтом, поэтому их не поймали бы ни сборка, ни тесты, ни локальный предпросмотр. Ниже — что это было, как убедиться, что у вас то же самое, и как это чинится. Пригодится, если вы попали сюда, вставив адрес из отчёта в поиск.

404: /cdn-cgi/l/email-protection

Симптом. Search Console → Страницы → Не найдено (404), и в списке ровно один адрес:

https://pavelsmolin.com/cdn-cgi/l/email-protection

Такой страницы на сайте нет, и в исходниках на неё никто не ссылается.

Причина. В Cloudflare по умолчанию включена Email Address Obfuscation (раздел Scrape Shield). На границе сети она переписывает каждый email-адрес в HTML. Обычная ссылка

<a href="mailto:hello@pavelsmolin.com">hello@pavelsmolin.com</a>

доходит до браузера как ссылка на /cdn-cgi/l/email-protection#<код> плюс маленький скрипт, который раскодирует адрес для людей. Задумано это против ботов: сборщик адресов видит закодированную строку, а не почту.

Googlebot её тоже видит. Фрагмент после # он отбрасывает (на сервер фрагменты вообще не отправляются), обходит голый /cdn-cgi/l/email-protection и получает 404. Теперь каждая страница, где есть email, ссылается в пустоту. У меня адрес стоит в футере, то есть это все страницы сайта.

Проверить можно за десять секунд:

curl -s -o /dev/null -w "%{http_code}\n" https://your-site.com/cdn-cgi/l/email-protection
# 404
curl -s https://your-site.com/ | grep -c "email-protection"
# больше нуля — значит, Cloudflare переписывает ваши адреса

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

Исправление. Два варианта:

  1. Выключить: панель Cloudflare → ваш домен → Scrape Shield → Email Address Obfuscation → off. Просто, и сразу для всех страниц.
  2. Оставить, но исключить адреса, которые вы публикуете сознательно. Всё, что стоит между этими маркерами, Cloudflare не трогает:
<!--email_off--><a href={`mailto:${SITE_EMAIL}`}>{SITE_EMAIL}</a><!--/email_off-->

На этой странице пример выше тоже обёрнут в эти маркеры, иначе пост про баг сам создал бы его новый экземпляр.

Я выбрал второй вариант для футера и страницы контактов: правка живёт в репозитории, её видно в ревью и в истории, как и всё остальное. Astro сохраняет HTML-комментарии в собранных страницах, Cloudflare срезает маркеры на границе сети, и в итоге на живой странице обычная ссылка mailto: без мёртвого адреса.

Ловушка — следующий адрес, который кто-нибудь добавит в компонент или в пост. Его снова перепишут, и Search Console сообщит об этом через несколько недель. Поэтому правило я записал туда, где его читают мои инструменты, а не только держу в голове.

Насколько запаздывает отчёт. Googlebot обошёл мёртвый адрес 7 сентября, Search Console показал его 15-го, исправление ушло в прод 16-го. После деплоя нажмите в этом отчёте Проверить исправление: Google обойдёт адрес заново и пришлёт письмо, когда закончит.

Вредит ли 404 на адресе, который вы и не собирались публиковать? По словам Google, сам по себе 404 на ранжирование не влияет. Но это ссылка с каждой страницы в никуда, мусор в отчёте, который хочется видеть пустым, и в моём случае — указатель на настройку, о которой я не знал.

525: запись www ведёт на страницу-парковку

Симптом. Search Console → Ошибка сервера (5xx) на www.pavelsmolin.com. В браузере — страница ошибки Cloudflare: 525: SSL handshake failed. Основной домен при этом работал.

Причина. 525 означает, что Cloudflare не смог завершить TLS-рукопожатие с вашим origin-сервером. Значит, вопрос в том, какой origin у www.

Оказалось, не тот:

www.pavelsmolin.com   CNAME   parkingpage.namecheap.com   Proxied

Это настройка Namecheap по умолчанию для только что купленного домена. При переезде на Cloudflare мастер подключения копирует существующие записи, так что этот хвост, скорее всего, приехал именно так. Сайт живёт на Cloudflare Pages, и к проекту Pages был привязан только основной домен. www по-прежнему смотрел на парковочную страницу Namecheap через прокси Cloudflare. По HTTPS рукопожатие падало — отсюда 525. С обычным http://www было хуже, просто тише: он отдавал парковочную страницу Namecheap с кодом 200 на моём домене.

dig этого не покажет: проксируемая запись резолвится в IP-адреса Cloudflare, а не в свою цель. Смотреть надо в DNS-записи в панели.

Исправление. Перенаправить www на границе сети, ещё до обращения к origin. Тогда старый CNAME ни на что не влияет — при условии, что запись остаётся проксируемой, потому что правило срабатывает только на проксируемом трафике. Rules → Redirect Rules → создать:

When:      Custom filter expression
           (http.host eq "www.pavelsmolin.com")
Then:      Dynamic redirect, 301
           concat("https://pavelsmolin.com", http.request.uri.path)
           Preserve query string: on

Два места, где я споткнулся:

  • Встроенный шаблон «Redirect from WWW to root» матчит только https://www.*. После его деплоя HTTPS заработал, а http://www так и отдавал парковку.
  • Режим wildcard не принимает маску протокола вида *://www.example.com/*. Условие на http.host в custom expression покрывает обе схемы.

Ещё Cloudflare предупредил, что правило «может не применяться», потому что DNS «может не проксировать трафик для www». Запись была проксируемой (оранжевое облако). Предупреждение ошибалось, и деплоить всё равно было правильно.

Проверка через curl — обе схемы, с путём и query-строкой:

for u in https://www.your-site.com/about/ "http://www.your-site.com/blog/?a=1"; do
  curl -s -o /dev/null -w "%{http_code} -> %{redirect_url}\n" "$u"
done
# 301 -> https://your-site.com/about/
# 301 -> https://your-site.com/blog/?a=1

Сколько это провисело. Впервые я увидел этот 525 в выгрузке отчёта 18 июля, а исправил 25 сентября. Диагноз занял минуты. Два месяца ушло потому, что исправление не было pull request’ом. Ошибку с email починили в тот же день, когда нашли, — её исправление жило в репозитории.

Тем временем счётчик 5xx в Search Console сам опустился до нуля. Это было не исправление: Google просто перестал обходить этот адрес.

Что я бы проверил на любом сайте за Cloudflare

  • Search Console → Страницы на новом ресурсе через месяц после запуска, дальше — раз в месяц. Всё под /cdn-cgi/ принадлежит Cloudflare, а не вам.
  • Каждую DNS-запись, которую принёс импорт. Парковочные записи регистратора — классический хвост.
  • www и основной домен, по http и по https. Четыре вызова curl. Каждый должен заканчиваться кодом 200 на одном каноническом хосте.
  • Всё, что Cloudflare переписывает на границе сети: обфускацию email, Rocket Loader, внедрённые скрипты. Google индексирует живой HTML, а не вашу сборку.

Вывод небольшой, но возвращается постоянно: чистая сборка доказывает, что в порядке репозиторий, и ничего не говорит о слое перед ним. Если ваш сайт стоит за Cloudflare, а Search Console показывает ошибки, которых вы не находите в коде, — напишите мне. Обычно это одна из этих двух.

Pavel Smolin · 28 октября 2026 г.

Похожие статьи

Руководство4 мин чтения

Как подключить MCP-сервер Supabase к Claude Code

Supabase подключается к Claude Code одной командой через хостируемый MCP-сервер: OAuth или personal access token, project_ref, read_only и какие инструменты разрешить.

Руководство3 мин чтения

Как подключить MCP-сервер RevenueCat к Claude Code

RevenueCat подключается к Claude Code двумя командами: официальный плагин или хостируемый MCP-сервер. OAuth или API-ключ, проверка и какие инструменты разрешить.