Jak naprawić błąd 404 na /cdn-cgi/l/email-protection w Search Console (zaciemnianie e-maili w Cloudflare)
Dwa błędy w Search Console, których mój kod nie wygenerował: zaciemnianie e-maili w Cloudflare tworzy adres 404, a rekord www wciąż wskazuje parking Namecheap.

Ta strona jest statyczna. Buduje ją Astro,
serwuje Cloudflare Pages, a CI sprawdza każdy pull request. Build nigdy nie
wygenerował zepsutego linku. Mimo to Search Console znalazł na niej dwa błędy:
Not found (404) i Server error (5xx).
Żaden nie pochodził z repozytorium. Oba wzięły się z konfiguracji Cloudflare, który stoi przed stroną, więc nie złapałby ich ani build, ani testy, ani lokalny podgląd. Poniżej: czym był każdy z nich, jak sprawdzić, czy masz to samo, i jak to naprawić — na wypadek, gdybyś trafił tu, wklejając adres z raportu do wyszukiwarki.
404: /cdn-cgi/l/email-protection
Objaw. Search Console → Strony → Nie znaleziono (404), a na liście dokładnie jeden adres:
https://pavelsmolin.com/cdn-cgi/l/email-protection
Takiej strony u mnie nie ma i nic w kodzie do niej nie linkuje.
Przyczyna. Cloudflare ma domyślnie włączone Email Address Obfuscation (sekcja Scrape Shield). Na brzegu sieci przepisuje każdy adres e-mail w HTML-u, więc zwykły link
<a href="mailto:hello@pavelsmolin.com">hello@pavelsmolin.com</a>
dociera do przeglądarki jako link do /cdn-cgi/l/email-protection#<kod> plus
mały skrypt, który odkodowuje adres dla ludzi. Chodzi o boty: zbieracz adresów
widzi zakodowany ciąg, a nie adres.
Googlebot też go widzi. Odrzuca fragment po # (fragmenty w ogóle nie trafiają
na serwer), odwiedza sam /cdn-cgi/l/email-protection i dostaje 404. Każda
strona z adresem e-mail linkuje teraz donikąd. U mnie adres jest w stopce, czyli
chodzi o wszystkie strony.
Sprawdzisz to w dziesięć sekund:
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"
# więcej niż zero — Cloudflare przepisuje twoje adresy
Drugie polecenie uruchom na żywej stronie. W lokalnym buildzie podmiany nie zobaczysz, bo powstaje dopiero wtedy, gdy stronę serwuje Cloudflare.
Poprawka. Dwie opcje:
- Wyłączyć: panel Cloudflare → twoja domena → Scrape Shield → Email Address Obfuscation → off. Proste i od razu dla wszystkich stron.
- Zostawić, ale wyłączyć adresy, które publikujesz świadomie. Tego, co stoi między tymi znacznikami, Cloudflare nie rusza:
<!--email_off--><a href={`mailto:${SITE_EMAIL}`}>{SITE_EMAIL}</a><!--/email_off-->
Na tej stronie przykład powyżej też jest owinięty w te znaczniki — inaczej wpis o błędzie sam stworzyłby jego nową instancję.
Wybrałem drugą opcję dla stopki i strony kontaktowej: poprawka żyje w
repozytorium, przechodzi przez review i ma historię jak wszystko inne. Astro
zostawia komentarze HTML w zbudowanych stronach, Cloudflare usuwa znaczniki na
brzegu sieci i na żywej stronie zostaje zwykły link mailto: bez martwego
adresu.
Pułapka to następny adres, który ktoś doda w komponencie albo we wpisie. Zostanie znowu przepisany, a Search Console powie o tym po kilku tygodniach. Dlatego zapisałem tę regułę tam, gdzie czytają ją moje narzędzia, a nie tylko w głowie.
Jak bardzo raport się spóźnia. Googlebot odwiedził martwy adres 7 września, Search Console pokazał go 15-go, a poprawka poszła na produkcję 16-go. Po wdrożeniu kliknij w tym raporcie Sprawdź poprawkę: Google odwiedzi adres ponownie i wyśle maila, kiedy skończy.
Czy 404 na adresie, którego nigdy nie chciałeś publikować, w ogóle szkodzi? Według Google sam 404 nie wpływa na ranking. Ale to link z każdej strony donikąd, bałagan w raporcie, który chcesz mieć pusty, a u mnie — trop do ustawienia, o którym nie wiedziałem.
525: rekord www wskazujący na stronę parkingową
Objaw. Search Console → Błąd serwera (5xx) na www.pavelsmolin.com.
W przeglądarce strona błędu Cloudflare: 525: SSL handshake failed. Domena
główna działała bez problemu.
Przyczyna. 525 oznacza, że brzeg sieci Cloudflare nie zdołał dokończyć
handshake’u TLS z serwerem origin. Pytanie brzmi więc: jaki origin ma www?
Okazało się, że nie ten:
www.pavelsmolin.com CNAME parkingpage.namecheap.com Proxied
To domyślne ustawienie Namecheap dla świeżo kupionej domeny. Przy przenosinach
do Cloudflare kreator kopiuje istniejące rekordy, więc ta pozostałość
najpewniej przyjechała właśnie tak. Strona działa na Cloudflare Pages, a do
projektu Pages była podpięta tylko domena główna. www nadal wskazywało na
stronę parkingową Namecheap, przez proxy Cloudflare. Po HTTPS handshake się
wysypywał — stąd 525. Zwykłe http://www było gorsze, tylko ciszej: serwowało
stronę parkingową Namecheap z kodem 200 pod moją domeną.
dig tego nie pokaże: rekord przez proxy rozwiązuje się na adresy IP
Cloudflare, a nie na swój cel. Trzeba zajrzeć do rekordów DNS w panelu.
Poprawka. Przekierować www na brzegu sieci, zanim w ogóle dojdzie do
originu. Wtedy stary CNAME przestaje mieć znaczenie — pod warunkiem, że rekord
zostaje przez proxy, bo reguła działa tylko na ruchu przechodzącym przez proxy.
Rules → Redirect Rules → utwórz:
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
Dwie rzeczy, na których się potknąłem:
- Wbudowany szablon „Redirect from WWW to root” dopasowuje tylko
https://www.*. Po jego wdrożeniu HTTPS działało, ahttp://wwwdalej serwowało parking. - Tryb wildcard odrzuca maskę protokołu w rodzaju
*://www.example.com/*. Warunek nahttp.hostw custom expression obejmuje oba schematy.
Cloudflare ostrzegł jeszcze, że reguła „może nie działać”, bo DNS „może nie przepuszczać ruchu www przez proxy”. Rekord był przez proxy (pomarańczowa chmurka). Ostrzeżenie się myliło i wdrożenie mimo to było właściwym ruchem.
Weryfikacja przez curl — oba schematy, ze ścieżką i query stringiem:
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
Jak długo to wisiało. Pierwszy raz zobaczyłem ten 525 w eksporcie raportu 18 lipca, a naprawiłem 25 września. Diagnoza zajęła minuty. Dwa miesiące zeszły, bo poprawka nie była pull requestem. Błąd z e-mailem naprawiłem tego samego dnia, w którym go znalazłem — jego poprawka żyła w repozytorium.
W międzyczasie licznik 5xx w Search Console sam spadł do zera. To nie była naprawa: Google po prostu przestał odwiedzać ten adres.
Co sprawdziłbym na każdej stronie za Cloudflare
- Search Console → Strony w nowej usłudze miesiąc po starcie, potem raz w
miesiącu. Wszystko pod
/cdn-cgi/należy do Cloudflare, nie do ciebie. - Każdy rekord DNS, który przyniósł import. Rekordy parkingowe rejestratora to klasyczna pozostałość.
wwwi domenę główną, pohttpi pohttps. Cztery wywołaniacurl. Każde powinno kończyć się kodem 200 na jednym kanonicznym hoście.- Wszystko, co Cloudflare przepisuje na brzegu sieci: zaciemnianie e-maili, Rocket Loader, wstrzykiwane skrypty. Google indeksuje żywy HTML, a nie twój build.
Wniosek jest niewielki, ale ciągle wraca: czysty build dowodzi, że w porządku jest repozytorium, i nic nie mówi o warstwie przed nim. Jeśli twoja strona stoi za Cloudflare, a Search Console pokazuje błędy, których nie możesz znaleźć w kodzie — napisz do mnie. Zwykle to jeden z tych dwóch.