{"id":2343,"date":"2025-12-03T13:55:00","date_gmt":"2025-12-03T12:55:00","guid":{"rendered":"https:\/\/jalvo.eu\/ukosnik-na-koncu-url-duplikaty-stron-nginx\/"},"modified":"2025-12-03T13:55:00","modified_gmt":"2025-12-03T12:55:00","slug":"ukosnik-na-koncu-url-duplikaty-stron-nginx","status":"publish","type":"post","link":"https:\/\/jalvo.eu\/pl\/ukosnik-na-koncu-url-duplikaty-stron-nginx\/","title":{"rendered":"Uko\u015bnik na ko\u0144cu adresu URL: jak naprawi\u0107 duplikaty stron na NGINX"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Adresy URL z uko\u015bnikiem na ko\u0144cu tworz\u0105 duplikaty stron, gdy <em>\/page<\/em> i <em>\/page\/<\/em> zwracaj\u0105 kod 200 z t\u0105 sam\u0105 tre\u015bci\u0105. Rozwi\u0105zanie jest proste. Wybierz jedn\u0105 form\u0119, a drug\u0105 przekieruj na ni\u0105 przez 301, na w\u0142asnym serwerze NGINX (origin) albo w CMS-ie. Widzisz w logach dost\u0119pu lub w Search Console t\u0119 sam\u0105 stron\u0119 dwa razy, raz z uko\u015bnikiem, a raz bez? To prawie zawsze w\u0142a\u015bnie z tego powodu. Poni\u017cej: wyb\u00f3r formy, sprawdzenie, co serwer zwraca w tej chwili, regu\u0142y NGINX i miejsce tag\u00f3w canonical (uprzedzam: to zabezpieczenie, a nie rozwi\u0105zanie).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Dlaczego \/page i \/page\/ to dwa r\u00f3\u017cne adresy URL?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Dla robota adres z uko\u015bnikiem na ko\u0144cu i adres bez niego to dwa osobne adresy. Nawet je\u015bli tre\u015b\u0107 jest identyczna co do bajtu. Takie rozdwojenie ma zwykle kilka przyczyn. Serwery WWW od dawna traktuj\u0105 \u015bcie\u017cki zako\u0144czone uko\u015bnikiem jak katalogi, a \u015bcie\u017cki bez niego jak pliki. Do tego dochodzi CMS, kt\u00f3ry generuje jedn\u0105 form\u0119, ale bez problemu przyjmuje obie. A linki wewn\u0119trzne i mapy witryny z czasem si\u0119 rozje\u017cd\u017caj\u0105, a\u017c zaczynaj\u0105 miesza\u0107 obie wersje. <a href=\"https:\/\/developers.google.com\/search\/docs\/crawling-indexing\/consolidate-duplicate-urls\" rel=\"nofollow noopener\" target=\"_blank\">Poradnik Google o \u0142\u0105czeniu zduplikowanych adres\u00f3w<\/a> wyja\u015bnia, ile to kosztuje: sygna\u0142y takie jak linki rozk\u0142adaj\u0105 si\u0119 na kopie, zamiast skupia\u0107 si\u0119 na jednym preferowanym adresie, a Googlebot traci czas na duplikaty zamiast na nowe lub zaktualizowane strony. Jedna rzecz, w kt\u00f3rej ludzie cz\u0119sto si\u0119 myl\u0105. \u017badna z form nie pozycjonuje si\u0119 lepiej. Problemem jest wy\u0142\u0105cznie posiadanie obu.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Wybierz jedn\u0105 form\u0119 adres\u00f3w z uko\u015bnikiem lub bez i trzymaj si\u0119 jej<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Obie formy s\u0105 w porz\u0105dku. Naprawd\u0119. Liczy si\u0119 <strong>sp\u00f3jno\u015b\u0107 adres\u00f3w URL<\/strong> w ca\u0142ym serwisie. Zacz\u0105\u0142bym od tego, co ju\u017c generuje Tw\u00f3j CMS, bo walka z jego struktur\u0105 bezpo\u015brednich odno\u015bnik\u00f3w oznacza tylko wi\u0119cej regu\u0142 do pilnowania p\u00f3\u017aniej. Nast\u0119pnie sprawd\u017a, kt\u00f3rej formy u\u017cywa wi\u0119kszo\u015b\u0107 link\u00f3w wewn\u0119trznych i zewn\u0119trznych. Przekierowanie mniejszej grupy oznacza mniej adres\u00f3w do ruszenia. Pliki to osobny przypadek: adresy ko\u0144cz\u0105ce si\u0119 na <em>.pdf<\/em>, <em>.xml<\/em> czy <em>.jpg<\/em> nigdy nie dostaj\u0105 uko\u015bnika.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Gdy ju\u017c zdecydujesz, wszystko musi wskazywa\u0107 t\u0119 sam\u0105 form\u0119:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>ustawienia bezpo\u015brednich odno\u015bnik\u00f3w w CMS-ie<\/li>\n<li>linki wewn\u0119trzne w tre\u015bci i szablonach<\/li>\n<li>mapa witryny XML<\/li>\n<li>menu nawigacyjne, okruszki i linki w stopce<\/li>\n<li>adnotacje hreflang, je\u015bli serwis ma wersje j\u0119zykowe<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Jak sprawdzi\u0107, co serwer zwraca dzisiaj<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Odpytaj obie wersje przez <code>curl -I<\/code> i por\u00f3wnaj kody odpowiedzi oraz nag\u0142\u00f3wki <em>Location<\/em>. Na przyk\u0142ad <code>curl -I https:\/\/example.com\/page<\/code>, a potem to samo z <em>\/page\/<\/em>. Dwa razy 200? Masz duplikaty. Chodzi Ci o 301 wskazuj\u0105ce wybran\u0105 form\u0119. A 302 to przekierowanie tymczasowe, wi\u0119c zamie\u0144 je na sta\u0142e.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Przy okazji sprawd\u017a, czy \u201ez\u0142a\u201d wersja nie serwuje ubogiej lub pustej strony z kodem 200. Niekt\u00f3re regu\u0142y awaryjne robi\u0105 dok\u0142adnie to (po cichu, oczywi\u015bcie), a Google mo\u017ce takie strony zaliczy\u0107 do <a href=\"https:\/\/jalvo.eu\/pl\/bledy-soft-404-strony-z-kodem-200\/\">stron uznanych przez Google za nieistniej\u0105ce<\/a>. I ostatnia rzecz: upewnij si\u0119, \u017ce przekierowanie trafia od razu na docelowy adres. Je\u015bli tworzy \u0142a\u0144cuch z osobnym przeskokiem z http na https albo na www, dok\u0142adasz kroki, kt\u00f3re mog\u0142a za\u0142atwi\u0107 jedna regu\u0142a.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Regu\u0142y rewrite w NGINX: dodawanie lub usuwanie uko\u015bnika przez 301<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">W NGINX jedna regu\u0142a rewrite w bloku server kieruje ka\u017cd\u0105 niepreferowan\u0105 wersj\u0119 na wybran\u0105 form\u0119 przez 301. Kolejno\u015b\u0107 dzia\u0142a\u0144:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Zr\u00f3b kopi\u0119 zapasow\u0105 konfiguracji serwisu, na przyk\u0142ad kopiuj\u0105c plik z <em>\/etc\/nginx\/sites-available\/<\/em>.<\/li>\n<li>Dodaj jedn\u0105 z poni\u017cszych regu\u0142 wewn\u0105trz bloku <code>server<\/code>.<\/li>\n<li>Uruchom <code>nginx -t<\/code>, \u017ceby sprawdzi\u0107 sk\u0142adni\u0119.<\/li>\n<li>Prze\u0142aduj konfiguracj\u0119 poleceniem <code>systemctl reload nginx<\/code>.<\/li>\n<li>Powt\u00f3rz sprawdzenie przez curl dla obu wersji kilku stron.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Aby usun\u0105\u0107 uko\u015bnik, bez ruszania prawdziwych katalog\u00f3w i katalogu g\u0142\u00f3wnego <em>\/<\/em>:<\/p>\n\n\n\n<pre><code>if (!-d $request_filename) {\n    rewrite ^\/(.+)\/$ \/$1 permanent;\n}<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Aby doda\u0107 uko\u015bnik, bez ruszania prawdziwych plik\u00f3w i \u015bcie\u017cek z rozszerzeniem pliku:<\/p>\n\n\n\n<pre><code>if (!-f $request_filename) {\n    rewrite ^([^.]*[^\/])$ $1\/ permanent;\n}<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Flaga <code>permanent<\/code> zwraca 301, co m\u00f3wi wyszukiwarkom, \u017ce przeniesienie jest ostateczne. Z kolei 302 oznacza, \u017ce pierwotny adres nadal obowi\u0105zuje. Nie rozstrzyga wi\u0119c, kt\u00f3r\u0105 wersj\u0119 zostawi\u0107. Wi\u0119cej o tym rozumowaniu znajdziesz w tek\u015bcie o <a href=\"https:\/\/jalvo.eu\/pl\/przekierowanie-301-czy-302-jak-wybrac-dla-seo\/\">regu\u0142ach 301 dla wariant\u00f3w adres\u00f3w<\/a>. A wed\u0142ug podlinkowanej wy\u017cej strony Google wszystkie metody sta\u0142ego przekierowania dzia\u0142aj\u0105 w wyszukiwarce tak samo. R\u00f3\u017cni\u0107 si\u0119 mo\u017ce jedynie czas, po jakim wyszukiwarki je zauwa\u017c\u0105.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dzia\u0142asz za reverse proxy, takim jak Jalvo? Wtedy regu\u0142a trafia na Tw\u00f3j serwer NGINX (origin) albo do CMS-a. Upewnij si\u0119 te\u017c, \u017ce origin nie jest dost\u0119pny pod drug\u0105 nazw\u0105 hosta. To ca\u0142y dodatkowy zestaw kopii, opisany w tek\u015bcie o <a href=\"https:\/\/jalvo.eu\/pl\/serwer-origin-poza-indeksem-google\/\">zduplikowanych hostach za proxy<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Gdzie pasuje kanoniczny adres URL<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Tag rel=canonical to wskaz\u00f3wka, kt\u00f3ra wspiera przekierowanie. Nie zast\u0119puje go. Strona Google wymienia trzy sposoby wskazania <strong>kanonicznego adresu URL<\/strong>. Po pierwsze, element <em>link<\/em> w sekcji <em>head<\/em> strony. Po drugie, nag\u0142\u00f3wek HTTP rel=canonical, przydatny przy plikach innych ni\u017c HTML, na przyk\u0142ad PDF. Po trzecie, podanie kanonicznych adres\u00f3w w mapie witryny, co Google okre\u015bla jako s\u0142abszy sygna\u0142 ni\u017c dwa pozosta\u0142e.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Moja rada: ustaw na ka\u017cdej stronie canonical wskazuj\u0105cy na ni\u0105 sam\u0105, zapisany w wybranej formie z uko\u015bnikiem lub bez, \u017ceby nigdy nie przeczy\u0142 przekierowaniu. Ustaw go w CMS-ie albo w szablonach stron na originie. Dzi\u0119ki temu nowe strony dostan\u0105 go automatycznie i nikt nie musi o tym pami\u0119ta\u0107.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Sp\u00f3jno\u015b\u0107 adres\u00f3w z uko\u015bnikiem na ko\u0144cu sprowadza si\u0119 wi\u0119c do kilku nawyk\u00f3w. Jedna forma. Jedna regu\u0142a 301 w NGINX albo w CMS-ie, kt\u00f3ra jej pilnuje. Canonicale i mapa witryny w tej samej formie. Po zmianie przejrzyj logi dost\u0119pu i Search Console i potwierd\u017a, \u017ce ka\u017cda strona jest pobierana i indeksowana tylko w jednej wersji. Potem zr\u00f3b to ponownie po aktualizacjach CMS-a lub zmianach w konfiguracji serwera, bo one potrafi\u0105 po cichu przywr\u00f3ci\u0107 drug\u0105 form\u0119.<\/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-1790771648469-0\" class=\"rank-math-list-item\">\n<h3 class=\"rank-math-question \">Czy uko\u015bnik na ko\u0144cu adresu wp\u0142ywa na pozycje?<\/h3>\n<div class=\"rank-math-answer \">\n\n<p>Nie. Wyszukiwarki nie preferuj\u0105 \u017cadnej z form. K\u0142opot zaczyna si\u0119 dopiero wtedy, gdy obie formy zwracaj\u0105 tre\u015b\u0107, co rozdziela sygna\u0142y, takie jak linki, mi\u0119dzy dwa adresy. Przekieruj jedn\u0105 form\u0119 na drug\u0105 i problem po prostu znika.<\/p>\n\n<\/div>\n<\/div>\n<div id=\"faq-question-1790771648469-1\" class=\"rank-math-list-item\">\n<h3 class=\"rank-math-question \">Czy tag canonical wystarczy bez przekierowania?<\/h3>\n<div class=\"rank-math-answer \">\n\n<p>Raczej nie. Tag canonical to wskaz\u00f3wka i wyszukiwarki mog\u0105 j\u0105 zignorowa\u0107. Przekierowanie 301 ca\u0142kowicie usuwa duplikat, bo druga wersja przestaje serwowa\u0107 tre\u015b\u0107. Przekierowanie jest rozwi\u0105zaniem. Canonical tylko je wspiera.<\/p>\n\n<\/div>\n<\/div>\n<div id=\"faq-question-1790771648469-2\" class=\"rank-math-list-item\">\n<h3 class=\"rank-math-question \">Czy strona g\u0142\u00f3wna lub adresy plik\u00f3w powinny mie\u0107 uko\u015bnik na ko\u0144cu?<\/h3>\n<div class=\"rank-math-answer \">\n\n<p>Domena g\u0142\u00f3wna dzia\u0142a tak samo w obu przypadkach, bo przegl\u0105darki i serwery traktuj\u0105 <em>example.com<\/em> i <em>example.com\/<\/em> jako jeden adres. Pliki takie jak <em>.pdf<\/em> czy <em>.xml<\/em> powinny zosta\u0107 bez uko\u015bnika. Obie powy\u017csze regu\u0142y NGINX i tak zostawiaj\u0105 te przypadki w spokoju.<\/p>\n\n<\/div>\n<\/div>\n<\/div>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>Adresy URL z uko\u015bnikiem na ko\u0144cu tworz\u0105 duplikaty stron, gdy \/page i \/page\/ zwracaj\u0105 kod 200 z t\u0105 sam\u0105 tre\u015bci\u0105. Rozwi\u0105zanie jest proste. Wybierz jedn\u0105 form\u0119, a drug\u0105 przekieruj na ni\u0105 przez 301, na w\u0142asnym serwerze NGINX (origin) albo w CMS-ie. Widzisz w logach dost\u0119pu lub w Search Console t\u0119 sam\u0105 stron\u0119 dwa razy, raz [&hellip;]<\/p>\n","protected":false},"author":25,"featured_media":2331,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[182],"tags":[288,247,347,402,35,415],"class_list":["post-2343","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-seo-pl","tag-duplikacja-tresci","tag-nginx-x","tag-przekierowania","tag-tagi-kanoniczne","tag-techniczne-seo-pl","tag-ukosnik-na-koncu-adresu"],"acf":[],"_links":{"self":[{"href":"https:\/\/jalvo.eu\/pl\/wp-json\/wp\/v2\/posts\/2343","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=2343"}],"version-history":[{"count":0,"href":"https:\/\/jalvo.eu\/pl\/wp-json\/wp\/v2\/posts\/2343\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/jalvo.eu\/pl\/wp-json\/wp\/v2\/media\/2331"}],"wp:attachment":[{"href":"https:\/\/jalvo.eu\/pl\/wp-json\/wp\/v2\/media?parent=2343"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jalvo.eu\/pl\/wp-json\/wp\/v2\/categories?post=2343"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jalvo.eu\/pl\/wp-json\/wp\/v2\/tags?post=2343"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}