{"id":2335,"date":"2025-03-24T13:09:00","date_gmt":"2025-03-24T12:09:00","guid":{"rendered":"https:\/\/jalvo.eu\/lancuchy-przekierowan-nginx-jak-znalezc-i-splaszczyc\/"},"modified":"2025-03-24T13:09:00","modified_gmt":"2025-03-24T12:09:00","slug":"lancuchy-przekierowan-nginx-jak-znalezc-i-splaszczyc","status":"publish","type":"post","link":"https:\/\/jalvo.eu\/pl\/lancuchy-przekierowan-nginx-jak-znalezc-i-splaszczyc\/","title":{"rendered":"\u0141a\u0144cuchy przekierowa\u0144: jak je znale\u017a\u0107 i sp\u0142aszczy\u0107 w NGINX"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">\u0141a\u0144cuch przekierowa\u0144 powstaje wtedy, gdy stary adres URL przechodzi przez kilka przekierowa\u0144, zanim dotrze do docelowej strony. Na przyk\u0142ad: najpierw http, potem www, potem uko\u015bnik na ko\u0144cu, a na koniec regu\u0142a dla starej \u015bcie\u017cki. Rozwi\u0105zanie polega na tym, \u017ceby ka\u017cdy stary URL kierowa\u0107 od razu na jego docelowy adres HTTPS jedn\u0105 regu\u0142\u0105 <code>return<\/code> w NGINX. Sk\u0105d si\u0119 bior\u0105 takie \u0142a\u0144cuchy? Zwykle narastaj\u0105 przy kolejnych przenosinach serwisu, bo ka\u017cda przeprowadzka dok\u0142ada\u0142a w\u0142asn\u0105 regu\u0142\u0119 do tych, kt\u00f3re zosta\u0142y po poprzedniej.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Czym s\u0105 \u0142a\u0144cuchy przekierowa\u0144 i dlaczego narastaj\u0105 po przenosinach serwisu?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">\u0141a\u0144cuch przekierowa\u0144 to seria przekierowa\u0144, w kt\u00f3rej ka\u017cdy skok prowadzi do kolejnego przekierowania zamiast do docelowej strony. Po kilku migracjach typowy \u0142a\u0144cuch wygl\u0105da tak:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>http:\/\/example.com\/old<\/code> &rarr; <code>https:\/\/example.com\/old<\/code> &rarr; <code>https:\/\/www.example.com\/old<\/code> &rarr; <code>https:\/\/www.example.com\/old\/<\/code> &rarr; <code>https:\/\/www.example.com\/new\/<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Cztery skoki. Dla jednej strony. Ka\u017cda przeprowadzka zostawia swoje regu\u0142y w osobnym bloku server albo location, a one uruchamiaj\u0105 si\u0119 jedna po drugiej. \u0141a\u0144cuch mimo wszystko ko\u0144czy si\u0119 na prawdziwej stronie i tym r\u00f3\u017cni si\u0119 od p\u0119tli, w kt\u00f3rej adres URL nigdy nie prowadzi do celu. Masz proxy przed serwerem \u017ar\u00f3d\u0142owym? Wtedy najpierw wyklucz schemat opisany w tek\u015bcie o <a href=\"https:\/\/jalvo.eu\/pl\/wordpress-za-reverse-proxy-przekierowania-i-https\/\">p\u0119tlach przekierowa\u0144 WordPressa za proxy<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Jak Google radzi sobie z wieloma przekierowaniami?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Googlebot pod\u0105\u017ca za przekierowaniami, a sta\u0142e przekierowania po stronie serwera m\u00f3wi\u0105 Google, \u017ce adres docelowy ma traktowa\u0107 jako kanoniczny. Wed\u0142ug <a href=\"https:\/\/developers.google.com\/search\/docs\/crawling-indexing\/301-redirects\" rel=\"nofollow noopener\" target=\"_blank\">wytycznych Google dotycz\u0105cych przekierowa\u0144<\/a> przekierowania po stronie serwera to metoda, kt\u00f3r\u0105 Google najpewniej odczyta poprawnie. Regu\u0142y NGINX wygrywaj\u0105 wi\u0119c z meta refresh i JavaScriptem. Strona Google nie podaje limitu skok\u00f3w. Ale pomy\u015bl: ka\u017cdy dodatkowy skok to jedno \u017c\u0105danie wi\u0119cej, zar\u00f3wno dla odwiedzaj\u0105cych, jak i dla robot\u00f3w, a nic w zamian nie zyskujesz. Wyb\u00f3r kodu statusu to osobna kwestia (opisujemy j\u0105 w poradniku o <a href=\"https:\/\/jalvo.eu\/pl\/przekierowanie-301-czy-302-jak-wybrac-dla-seo\/\">przekierowaniach sta\u0142ych i tymczasowych<\/a>).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Jak sprawdzi\u0107 przekierowania za pomoc\u0105 curl<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><code>curl -I<\/code> pokazuje kod statusu i nag\u0142\u00f3wek <code>Location<\/code> dla jednego skoku, bez pobierania strony. Dodaj <code>-L<\/code>, \u017ceby prze\u015bledzi\u0107 ca\u0142\u0105 \u015bcie\u017ck\u0119, a potem przefiltruj wynik tak, \u017ceby zosta\u0142y same skoki:<\/p>\n\n\n\n<pre><code>curl -sIL http:\/\/example.com\/old | grep -Ei '^(HTTP|location)'<\/code><\/pre>\n<p class=\"wp-block-paragraph\">W praktyce przeprowadzi\u0142bym audyt tak:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Zbierz stare adresy URL z dawnych map witryny, raport\u00f3w link\u00f3w zwrotnych i wcze\u015bniejszych map przekierowa\u0144.<\/li>\n<li>Sprawd\u017a ka\u017cd\u0105 \u015bcie\u017ck\u0119 we wszystkich czterech wariantach: http i https, z www i bez.<\/li>\n<li>Zapisz liczb\u0119 skok\u00f3w i ko\u0144cowy URL dla ka\u017cdego wariantu.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Kr\u00f3tka p\u0119tla wska\u017ce ka\u017cdy URL, kt\u00f3ry zwraca wi\u0119cej ni\u017c jeden nag\u0142\u00f3wek <code>Location<\/code>:<\/p>\n\n\n\n<pre><code>while read -r url; do\n  n=$(curl -sIL \"$url\" | grep -ci '^location:')\n  [ \"$n\" -gt 1 ] &amp;&amp; echo \"$n hops: $url\"\ndone &lt; urls.txt<\/code><\/pre>\n<p class=\"wp-block-paragraph\">P\u0119tle wygl\u0105daj\u0105 inaczej. curl pod\u0105\u017ca za przekierowaniami, a\u017c dojdzie do limitu <code>--max-redirs<\/code>, a potem przerywa z b\u0142\u0119dem. \u017badnego ko\u0144cowego 200.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Sp\u0142aszczanie \u0142a\u0144cuch\u00f3w przekierowa\u0144 regu\u0142ami return w NGINX<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Pomys\u0142 jest prosty. Zbuduj pe\u0142ny docelowy URL (w\u0142a\u015bciwy protok\u00f3\u0142, w\u0142a\u015bciwy host, w\u0142a\u015bciwa \u015bcie\u017cka) w jednym <code>return 301<\/code>, tak \u017ceby ka\u017cde niekanoniczne \u017c\u0105danie trafia\u0142o do celu w jednym skoku. Jeden blok \u0142api\u0105cy wszystko, kt\u00f3ry wysy\u0142a na <code>https:\/\/www.example.com$request_uri<\/code>, zast\u0119puje osobne regu\u0142y z http na https i dla www. Stare \u015bcie\u017cki trafiaj\u0105 do <code>map<\/code>, sprawdzanej przed przekierowaniem hosta, wi\u0119c stara \u015bcie\u017cka przeskakuje od razu na docelow\u0105 stron\u0119. I ka\u017cdy adres docelowy zapisuj z uko\u015bnikiem na ko\u0144cu. Inaczej po drodze odpali si\u0119 regu\u0142a dla uko\u015bnika i znowu masz dwa skoki. Przy zwyk\u0142ych przenosinach jeden do jednego <code>return<\/code> jest czytelniejszy i ta\u0144szy ni\u017c <code>rewrite<\/code>, bez dyskusji.<\/p>\n\n\n\n<pre><code>map $uri $legacy_target {\n    default   \"\";\n    \/old      https:\/\/www.example.com\/new\/;\n    \/old\/     https:\/\/www.example.com\/new\/;\n}\n\nserver {\n    listen 80;\n    server_name example.com www.example.com;\n    if ($legacy_target) { return 301 $legacy_target; }\n    return 301 https:\/\/www.example.com$request_uri;\n}\n\nserver {\n    listen 443 ssl;\n    server_name example.com;\n    if ($legacy_target) { return 301 $legacy_target; }\n    return 301 https:\/\/www.example.com$request_uri;\n}\n\nserver {\n    listen 443 ssl;\n    server_name www.example.com;\n    if ($legacy_target) { return 301 $legacy_target; }\n    # konfiguracja serwisu\n}<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Wi\u0119ksza migracja? To samo, tylko wi\u0119cej linii. Podej\u015bcie do <a href=\"https:\/\/jalvo.eu\/pl\/zmiana-domeny-bez-utraty-seo-plan-przeprowadzki\/\">map przekierowa\u0144 przy przenosinach serwisu<\/a> rozszerza dok\u0142adnie t\u0119 map\u0119 do tysi\u0119cy wpis\u00f3w.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Testowanie i utrzymanie sp\u0142aszczonych regu\u0142<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Uruchom <code>nginx -t<\/code>, prze\u0142aduj konfiguracj\u0119, a potem przepu\u015b\u0107 t\u0119 sam\u0105 list\u0119 przez curl jeszcze raz. Ka\u017cdy stary URL powinien teraz zwraca\u0107 jedno 301, a potem 200. I tyle. Nast\u0119pnie zaktualizuj linki wewn\u0119trzne, tagi canonical i map\u0119 witryny na adresy docelowe, \u017ceby serwis sam nie tworzy\u0142 nowych skok\u00f3w. Trzymaj jeden plik z map\u0105 przekierowa\u0144 w systemie kontroli wersji. Gdy strona znowu si\u0119 przeniesie, edytuj istniej\u0105ce adresy docelowe zamiast dok\u0142ada\u0107 now\u0105 regu\u0142\u0119 na wierzch (dok\u0142adnie tak powsta\u0142 ten \u0142a\u0144cuch). Przy reverse proxy przed serwerem przekierowania nadal siedz\u0105 w NGINX na serwerze \u017ar\u00f3d\u0142owym. Upewnij si\u0119 tylko, \u017ce proxy przekazuje \u017c\u0105dania tak, \u017ceby serwer \u017ar\u00f3d\u0142owy widzia\u0142 w\u0142a\u015bciwy protok\u00f3\u0142 i host. Je\u015bli nie, regu\u0142y dopasuj\u0105 si\u0119 do z\u0142ego bloku.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u0141a\u0144cuchy zostaj\u0105 naprawione tylko wtedy, gdy kto\u015b faktycznie za nie odpowiada. Sprawd\u017a stare adresy przez curl, po\u0142\u0105cz regu\u0142y protoko\u0142u i www w jeden return, skieruj stare \u015bcie\u017cki prosto na docelowe adresy i powtarzaj testy po ka\u017cdych kolejnych przenosinach. Nic efektownego, ale dzia\u0142a.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">FAQ<\/h2>\n\n\n<div id=\"rank-math-faq\" class=\"rank-math-block\">\n<div class=\"rank-math-list \">\n<div id=\"faq-question-1790771535663-0\" class=\"rank-math-list-item\">\n<h3 class=\"rank-math-question \">Ile przekierowa\u0144 mo\u017ce mie\u0107 \u0142a\u0144cuch, zanim stanie si\u0119 problemem?<\/h3>\n<div class=\"rank-math-answer \">\n\n<p>Celuj w jeden skok na ka\u017cdy stary URL. Ka\u017cde dodatkowe przekierowanie to kolejne \u017c\u0105danie dla u\u017cytkownik\u00f3w i robot\u00f3w, a nic w zamian nie dostajesz. Je\u015bli audyt pokazuje dwa skoki lub wi\u0119cej, skieruj ten URL prosto na jego docelowy adres.<\/p>\n\n<\/div>\n<\/div>\n<div id=\"faq-question-1790771535663-1\" class=\"rank-math-list-item\">\n<h3 class=\"rank-math-question \">Czy \u0142a\u0144cuch przekierowa\u0144 z http na https i przekierowanie www mo\u017cna po\u0142\u0105czy\u0107 w jedn\u0105 regu\u0142\u0119?<\/h3>\n<div class=\"rank-math-answer \">\n\n<p>Tak. Jedno <code>return 301 https:\/\/www.example.com$request_uri;<\/code> w bloku, kt\u00f3ry \u0142apie zwyk\u0142e http i niekanoniczny host, obs\u0142uguje oba przypadki naraz. Z dowolnego wariantu na kanoniczny URL w jednym kroku.<\/p>\n\n<\/div>\n<\/div>\n<div id=\"faq-question-1790771535663-2\" class=\"rank-math-list-item\">\n<h3 class=\"rank-math-question \">Czym r\u00f3\u017cni si\u0119 \u0142a\u0144cuch przekierowa\u0144 od p\u0119tli przekierowa\u0144?<\/h3>\n<div class=\"rank-math-answer \">\n\n<p>\u0141a\u0144cuch ko\u0144czy si\u0119 na stronie po kilku skokach. P\u0119tla odsy\u0142a \u017c\u0105danie z powrotem do wcze\u015bniejszego adresu URL i nigdy si\u0119 nie ko\u0144czy. W <code>curl -sIL<\/code> \u0142a\u0144cuch pokazuje kilka linii <code>Location<\/code>, a potem 200. P\u0119tla po prostu si\u0119 powtarza, a\u017c curl si\u0119 podda z b\u0142\u0119dem przekroczenia maksymalnej liczby przekierowa\u0144.<\/p>\n\n<\/div>\n<\/div>\n<\/div>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>\u0141a\u0144cuch przekierowa\u0144 powstaje wtedy, gdy stary adres URL przechodzi przez kilka przekierowa\u0144, zanim dotrze do docelowej strony. Na przyk\u0142ad: najpierw http, potem www, potem uko\u015bnik na ko\u0144cu, a na koniec regu\u0142a dla starej \u015bcie\u017cki. Rozwi\u0105zanie polega na tym, \u017ceby ka\u017cdy stary URL kierowa\u0107 od razu na jego docelowy adres HTTPS jedn\u0105 regu\u0142\u0105 return w NGINX. [&hellip;]<\/p>\n","protected":false},"author":25,"featured_media":2307,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[182],"tags":[350,247,347,28,35],"class_list":["post-2335","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-seo-pl","tag-migracja-serwisu","tag-nginx-x","tag-przekierowania","tag-seo-pl","tag-techniczne-seo-pl"],"acf":[],"_links":{"self":[{"href":"https:\/\/jalvo.eu\/pl\/wp-json\/wp\/v2\/posts\/2335","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jalvo.eu\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jalvo.eu\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jalvo.eu\/pl\/wp-json\/wp\/v2\/users\/25"}],"replies":[{"embeddable":true,"href":"https:\/\/jalvo.eu\/pl\/wp-json\/wp\/v2\/comments?post=2335"}],"version-history":[{"count":0,"href":"https:\/\/jalvo.eu\/pl\/wp-json\/wp\/v2\/posts\/2335\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/jalvo.eu\/pl\/wp-json\/wp\/v2\/media\/2307"}],"wp:attachment":[{"href":"https:\/\/jalvo.eu\/pl\/wp-json\/wp\/v2\/media?parent=2335"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jalvo.eu\/pl\/wp-json\/wp\/v2\/categories?post=2335"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jalvo.eu\/pl\/wp-json\/wp\/v2\/tags?post=2335"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}