Plik .htaccess - przekierowania i konfiguracja pod SEO

Poprawna konfiguracja pliku .htaccess to fundament skutecznego wdrożenia przekierowań 301 i optymalizacji technicznego SEO na serwerze Apache. W tym poradniku zebraliśmy gotowe reguły pozwalające uporządkować strukturę adresów URL, wdrożyć bezpieczne połączenie HTTPS oraz uniknąć błędów indeksacji. Dowiesz się także, jak przygotować serwer do odczytu dyrektyw i zadbać o bezproblemowe działanie modułu mod_rewrite.
Plik .htaccess - przekierowania i konfiguracja pod SEO

Plik .htaccess to plik konfiguracyjny serwera Apache, który pozwala ustawić przekierowania, kompresję i nagłówki dla wybranego katalogu strony internetowej bez dostępu do głównej konfiguracji serwera. W SEO używa się go przede wszystkim do przekierowań 301: z HTTP na HTTPS, między wersją z www i bez, ze starych adresów na nowe po zmianie struktury serwisu.

Każda reguła ma tu kod do skopiowania i krótkie wyjaśnienie, co robi. Stan wiedzy: 15 października 2026. Składnię sprawdziliśmy w dokumentacji Apache HTTP Server 2.4, a zachowanie Google w Google Search Central.

Czym jest plik .htaccess i kiedy serwer go czyta?

Plik .htaccess to tak zwany plik konfiguracji rozproszonej. Kropka na początku nazwy oznacza w systemach uniksowych plik ukryty, dlatego w menedżerze plików hostingu trzeba czasem włączyć pokazywanie ukrytych plików. Zwykle leży w katalogu głównym strony ( public_html, www, htdocs) i działa na ten katalog oraz wszystkie podkatalogi. Plik w podkatalogu może nadpisać reguły z katalogu wyżej.

Serwer czyta .htaccess tylko wtedy, gdy główna konfiguracja na to pozwala. Decyduje o tym dyrektywa AllowOverride, której domyślna wartość w Apache 2.4 to None. Przy None zawartość pliku .htaccess jest całkowicie ignorowana, a reguły nie dają ani efektu, ani błędu. Na hostingu współdzielonym jest to zwykle włączone, na własnym VPS-ie często trzeba to zrobić samodzielnie.

Do przekierowań przez mod_rewrite potrzebne są dwie rzeczy jednocześnie:

  • AllowOverride musi obejmować FileInfo, bo to ta grupa dopuszcza dyrektywy RewriteEngine, RewriteCond i RewriteRule,
  • musi być włączona opcja FollowSymLinks albo SymLinksIfOwnerMatch.

Schemat w dwóch częściach. Po lewej: AllowOverride w konfiguracji serwera z dwiema gałęziami, None (wartość domyślna w Apache 2.4, plik ignorowany bez błędu) oraz FileInfo z FollowSymLinks (reguły mod_rewrite działają). Po prawej: drzewo katalogu public_html z plikiem .htaccess działającym na wszystkie podkatalogi i drugim plikiem w katalogu sklep, który nadpisuje reguły tylko dla niego

Rys. 1. Dwa pytania przed każdą zmianą: czy serwer czyta plik i których katalogów reguła dotyczy.

Jak utworzyć i edytować plik .htaccess?

Plik .htaccess to zwykły plik tekstowy bez rozszerzenia. Treść pliku .htaccess można edytować na trzy sposoby:

  • Menedżer plików w panelu hostingu. Najprostsza droga: otwieracie katalog główny strony, włączacie pokazywanie plików ukrytych i edytujecie plik w przeglądarce.
  • Klient FTP. Łączycie się z serwerem FTP (np. FileZillą), pobieracie plik, zmieniacie go lokalnie i wgrywacie z powrotem w to samo miejsce.
  • Edytor tekstu na komputerze. Wystarczy najprostszy edytor tekstowy, na przykład Notatnik. Word i podobne edytory dokumentów dopisują formatowanie, którego serwer nie zrozumie.

Jeśli pliku nie ma, trzeba utworzyć plik .htaccess samodzielnie. W Notatniku przy zapisie wybierzcie „Wszystkie pliki” jako typ i wpiszcie nazwę .htaccess. Inaczej system zapisze go jako .htaccess.txt i serwer go pominie. Kodowanie: UTF-8.

Przed każdą zmianą zróbcie kopię pliku .htaccess. Jedna literówka w dyrektywie potrafi wyłączyć całą stronę błędem 500, a kopia pozwala wrócić do działającej wersji w kilka sekund.

Gdzie jest plik .htaccess w WordPressie i do czego służy przy przyjaznych linkach?

W katalogu głównym instalacji, w tym samym folderze co wp-config.php. WordPress używa go do obsługi przyjaznych linków, czyli bezpośrednich odnośników typu /blog/plik-htaccess/ zamiast /?p=123. Jeśli pliku nie ma albo został uszkodzony, domyślny blok według dokumentacji WordPressa wygląda tak:

# BEGIN WordPress
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# END WordPress

Prostszy sposób na odtworzenie: w panelu administracyjnym WordPressa wejdźcie w Ustawienia, Bezpośrednie odnośniki i kliknijcie Zapisz zmiany bez zmieniania czegokolwiek. Jeśli WordPress ma uprawnienia do zapisu, sam utworzy ten blok.

Czy .htaccess to najlepsze miejsce na przekierowania?

Nie zawsze. Dokumentacja Apache wprost zaleca, żeby reguły, także mod_rewrite, trzymać w głównej konfiguracji serwera, jeśli ma się do niej dostęp. Powód jest wydajnościowy: konfiguracja główna wczytuje się raz przy starcie serwera, a zawartość pliku .htaccess przy każdym żądaniu. Gdy .htaccess są dozwolone, Apache szuka ich w każdym katalogu na ścieżce do pliku, nawet jeśli żadnego nie ma.

W praktyce na hostingu współdzielonym i w większości instalacji WordPressa .htaccess jest jedynym miejscem, do którego macie dostęp, więc to tam lądują przekierowania. Jeśli administrujecie serwerem samodzielnie, przenieście reguły do konfiguracji vhosta. Składnia jest prawie taka sama, różni się dopasowaniem ścieżki (o tym niżej).

Na serwerze Nginx pliku .htaccess nie ma w ogóle, a reguły trzeba przepisać na składnię Nginx.

Sprawdźmy potencjał Twojej strony

Podaj adres swojej strony i e-mail - odezwiemy się z konkretną analizą, bez zobowiązań.

Dane posłużą tylko do kontaktu. Zobacz Politykę prywatności.

Super! Odezwiemy się wkrótce!

Coś poszło nie tak podczas wysyłania formularza. Spróbuj ponownie.

Który kod przekierowania wpisać w .htaccess?

Przy trwałej zmianie adresu 301, przy tymczasowej 302. Google traktuje 301 i 308 jako przekierowania stałe, a 302, 303 i 307 jako tymczasowe. Różnice między kodami i ich wpływ na SEO opisaliśmy osobno w tekście przekierowanie strony i domeny, a pełną listę kodów, także 4xx i 5xx, w tekście o kodach odpowiedzi HTTP.

W pliku .htaccess kod podaje się w nawiasie: [R=301]. Sama flaga [R] bez liczby to dla Apache przekierowanie 302, czyli tymczasowe. Łatwo to przeoczyć, bo przekierowanie działa i w przeglądarce niczym się nie różni. W mod_alias odpowiednikiem jest słowo permanent albo liczba: Redirect 301. Samo Redirect bez kodu również daje 302.

Przekierowanie HTTP na HTTPS w .htaccess, razem z www

Typowe zadanie to ujednolicenie adresu domeny: wymuszenie HTTPS i jednej wersji strony, z www albo bez. Zanim je wdrożycie, sprawdźcie, czy certyfikat SSL działa dla obu wariantów domeny, bo inaczej przekierowanie skończy się ostrzeżeniem w przeglądarce. Robi się to jedną regułą, tak żeby każdy wariant adresu URL trafiał do celu jednym skokiem. Dwie osobne reguły (najpierw HTTPS, potem www) dają dla adresu http://www. łańcuch dwóch przekierowań.

Porównanie dwóch konfiguracji. Po lewej dwie osobne reguły: adres http://www.example.pl/kontakt/ przechodzi przez https://www.example.pl/kontakt/ do https://example.pl/kontakt/, czyli dwa przekierowania 301. Po prawej jedna reguła z warunkiem OR prowadzi z tego samego adresu do celu jednym przekierowaniem 301

Rys. 2. Ten sam adres wejściowy i docelowy, ale przy dwóch regułach robot przechodzi przez adres pośredni.

Wersja bez www:

RewriteEngine On

RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteRule ^ https://example.pl%{REQUEST_URI} [R=301,L,NE]

Wersja z www:

RewriteEngine On

RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.example.pl%{REQUEST_URI} [R=301,L,NE]

Co tu się dzieje:

  • %{HTTPS} ma wartość on przy połączeniu szyfrowanym i off w pozostałych przypadkach,
  • [OR] łączy warunki przez „lub” zamiast domyślnego „i”,
  • domena jest wpisana na sztywno, więc reguła zawsze prowadzi do jednego adresu docelowego, niezależnie od tego, z której wersji przyszło żądanie,
  • %{REQUEST_URI} przenosi ścieżkę, a parametry po ? Apache dołącza sam,
  • NE wyłącza ponowne kodowanie znaków, które w REQUEST_URI są już zakodowane.

HTTPS za Cloudflare lub innym proxy

Jeśli strona stoi za Cloudflare, load balancerem albo serwerem proxy, reguła z %{HTTPS} off może wywołać pętlę. Proxy przyjmuje ruch po HTTPS, ale do serwera łączy się po HTTP, więc serwer zawsze widzi off i przekierowuje w nieskończoność. Cloudflare opisuje to wprost w swojej dokumentacji jako przyczynę ERR_TOO_MANY_REDIRECTS przy trybie SSL „Flexible” i zaleca przełączenie na tryb „Full” lub wyższy albo usunięcie przekierowania na serwerze.

Gdy proxy przekazuje oryginalny protokół w nagłówku X-Forwarded-Proto, warunek można oprzeć na nim:

RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^ https://example.pl%{REQUEST_URI} [R=301,L,NE]

Tego wariantu używajcie tylko wtedy, gdy wiecie, że cały ruch przechodzi przez proxy, które ten nagłówek ustawia.

HSTS po przejściu na HTTPS

Gdy HTTPS działa stabilnie, warto dodać nagłówek HSTS. Przeglądarka po pierwszej wizycie sama zamienia http:// na https:// i pomija przekierowanie. Wymaga modułu mod_headers:

<IfModule mod_headers.c>
  Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</IfModule>

Do listy preload (hstspreload.org) potrzebne są max-age co najmniej 31 536 000 sekund (rok), includeSubDomains i dyrektywa preload. Serwis ostrzega, że wpisu na listę nie da się łatwo cofnąć. Najpierw upewnijcie się, że każda subdomena ma działający certyfikat.

Przekierowania 301 w .htaccess: adresy, katalogi i parametry

Apache daje dwa narzędzia do przekierowań. Redirect i RedirectMatch z modułu mod_alias wystarczają do prostych przypadków. RewriteRule z mod_rewrite jest potrzebne, gdy warunek dotyczy domeny, protokołu albo parametrów w adresie.

Naszym zdaniem lepiej nie mieszać obu modułów w jednym pliku. Każdy z nich przetwarza żądanie niezależnie, więc kolejność linii w pliku nie mówi, która reguła zadziała pierwsza. Jeśli w pliku jest już RewriteEngine On, piszcie wszystkie przekierowania jako RewriteRule.

Pojedynczy adres

Przez mod_alias:

Redirect 301 /stary-adres/ https://example.pl/nowy-adres/

Pułapka: Redirect dopasowuje prefiks ścieżki. Reguła z /stary-adres/ przekieruje też /stary-adres/cokolwiek na /nowy-adres/cokolwiek. Gdy chcecie przekierować dokładnie jeden adres, użyjcie RedirectMatch z kotwicami:

RedirectMatch 301 ^/stary-adres/?$ https://example.pl/nowy-adres/

Przez mod_rewrite:

RewriteRule ^stary-adres/?$ /nowy-adres/ [R=301,L]

Zwróćcie uwagę na brak ukośnika po ^. W pliku .htaccess Apache obcina ścieżkę katalogu przed dopasowaniem, więc wzorzec zaczynający się od ^/ nigdy nie zadziała. Stąd reguły skopiowane z konfiguracji vhosta, które w .htaccess „nic nie robią”. /? dopuszcza adres z ukośnikiem na końcu i bez niego, ^ i $ blokują dopasowanie dłuższych ścieżek.

Cały katalog z zachowaniem podstron

RewriteRule ^blog/(.*)$ /poradnik/$1 [R=301,L]

Nawiasy (.*) przechwytują resztę ścieżki, a $1 wstawia ją w adres docelowy. /blog/plik-htaccess/ trafi na /poradnik/plik-htaccess/.

Flaga QSA nie jest tu potrzebna. Gdy adres docelowy nie zawiera własnego ?, Apache domyślnie kopiuje parametry z oryginalnego żądania. QSA ma znaczenie dopiero wtedy, gdy w adresie docelowym dopisujecie nowe parametry i chcecie zachować też stare.

Stare adresy z parametrami

Wzorzec w RewriteRule nie widzi części po znaku zapytania. Do parametrów służy warunek na %{QUERY_STRING}:

RewriteCond %{QUERY_STRING} (^|&)id=42(&|$)
RewriteRule ^produkt\.php$ /buty-biegowe/ [R=301,L,QSD]

QSD usuwa stary parametr z adresu docelowego. Bez tej flagi przekierowanie prowadziłoby na /buty-biegowe/?id=42.

Przekierowanie całej domeny na inną domenę

Przy zmianie domeny każda podstrona starej domeny powinna trafić na swój odpowiednik pod nowym adresem, a nie na stronę główną. Jeśli struktura adresów się nie zmienia, wystarczy jedna reguła w .htaccess starej domeny:

RewriteEngine On
RewriteCond %{HTTP_HOST} ^(www\.)?stara-domena\.pl$ [NC]
RewriteRule ^(.*)$ https://nowa-domena.pl/$1 [R=301,L]

Warunek obejmuje wersję z www i bez, a $1 przenosi ścieżkę. /kontakt/ na starej domenie trafi na https://nowa-domena.pl/kontakt/. Stara domena musi dalej wskazywać na serwer z tym plikiem, a nie od razu na nową domenę, więc nie wyłączajcie jej hostingu zaraz po migracji.

Końcowy ukośnik

/kategoria i /kategoria/ to dla Google dwa różne adresy. Jeśli oba zwracają 200 z tą samą treścią, powstaje duplikat. Wybierzcie jedną wersję i przekierujcie drugą.

Dodawanie ukośnika (z pominięciem plików, żeby nie psuć /style.css):

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !/$
RewriteRule ^ %{REQUEST_URI}/ [R=301,L]

Usuwanie ukośnika (z pominięciem prawdziwych katalogów):

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [R=301,L]

Dla fizycznych katalogów Apache sam dodaje ukośnik przekierowaniem, bo tak działa domyślnie włączona dyrektywa DirectorySlash z modułu mod_dir. Dokumentacja ostrzega przed jej wyłączaniem ze względów bezpieczeństwa. W WordPressie format ukośnika ustala struktura bezpośrednich odnośników (Ustawienia, Bezpośrednie odnośniki) i CMS sam przekierowuje drugą wersję. Reguła w .htaccess, która narzuca odwrotny format, kończy się pętlą.

Treść usunięta na stałe: 410

Nie każdy stary adres trzeba przekierować. Jeśli treść zniknęła i nie ma odpowiednika, kod 410 Gone mówi wprost, że zasób został usunięty celowo:

Redirect gone /stara-promocja/

albo w mod_rewrite flagą G:

RewriteRule ^stara-promocja/?$ - [G]

Przekierowanie wszystkich usuniętych adresów na stronę główną to zły pomysł. Google w dokumentacji o migracjach odradza kierowanie wielu starych adresów na jeden niepowiązany adres, na przykład na stronę główną nowego serwisu.

Kolejność reguł w WordPressie i innych CMS

Własne przekierowania wpisujcie nad blokiem # BEGIN WordPress. Apache czyta plik od góry. Blok WordPressa kończy się regułą, która każde żądanie niebędące plikiem ani katalogiem (!-f, !-d) przekazuje do index.php z flagą [L]. Przekierowania wpisane pod nim nie zadziałają dla adresów generowanych przez CMS.

Schemat pliku .htaccess czytanego od góry: na górze blok Przekierowania SEO z regułami HTTPS i przekierowaniem 301, który działa; w środku blok WordPress z regułą RewriteRule . /index.php [L], która kieruje każdy adres wirtualny do index.php; na dole reguła dopisana na końcu pliku, która nie zadziała dla adresów CMS

Rys. 3. Reguła dopisana pod blokiem WordPressa wygląda poprawnie, ale Apache do niej nie dochodzi.

Przy zapisie bezpośrednich odnośników WordPress nadpisuje tylko tekst między własnymi znacznikami `

BEGIN WordPressi

END WordPress`. Reguły nad

blokiem zostają. Dla porządku oznaczcie je własnymi komentarzami:

# BEGIN Przekierowania SEO
RewriteEngine On
RewriteBase /

RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteRule ^ https://example.pl%{REQUEST_URI} [R=301,L,NE]

RewriteRule ^stary-adres/?$ /nowy-adres/ [R=301,L]
# END Przekierowania SEO

# BEGIN WordPress
...
# END WordPress

Wtyczki do cache i bezpieczeństwa też dopisują własne bloki do pliku .htaccess. Przed każdą zmianą sprawdźcie, co już jest w pliku, i nie usuwajcie bloków, których nie rozumiecie.

Druga pułapka dotyczy flagi L. W .htaccess zatrzymuje ona tylko bieżący przebieg reguł. Jeśli adres został przepisany wewnętrznie, Apache może przetworzyć go od początku jeszcze raz, co bywa źródłem pętli. Dokumentacja Apache zaleca w kontekście katalogu flagę END, która kończy przetwarzanie całkowicie. Przy przekierowaniach zewnętrznych (R=301) problem nie występuje, bo odpowiedź od razu wraca do przeglądarki.

Kompresja i cache przeglądarki w .htaccess

Plik .htaccess przydaje się też do ustawień, które przyspieszają ładowanie strony internetowej. Tu pokazujemy dwa: kompresję odpowiedzi ( mod_deflate) i czas przechowywania plików statycznych w przeglądarce ( mod_expires).

<IfModule mod_deflate.c>
  AddOutputFilterByType DEFLATE text/html text/css text/plain text/xml
  AddOutputFilterByType DEFLATE application/javascript application/json image/svg+xml
</IfModule>

<IfModule mod_expires.c>
  ExpiresActive On
  ExpiresByType image/webp "access plus 1 year"
  ExpiresByType image/jpeg "access plus 1 year"
  ExpiresByType image/png "access plus 1 year"
  ExpiresByType text/css "access plus 1 month"
  ExpiresByType application/javascript "access plus 1 month"
</IfModule>

Długi czas przechowywania w pamięci podręcznej ustawiajcie tylko dla plików, które przy zmianie dostają nową nazwę albo parametr wersji (style.css?ver=2). Inaczej użytkownicy przez miesiąc będą oglądać stary arkusz stylów. HTML zostawcie bez długiego cache.

Tu blok <IfModule> ma sens: jeśli moduł nie jest załadowany, strona działa dalej, tylko bez kompresji. Przy przekierowaniach jest odwrotnie (patrz diagnostyka niżej).

Własna strona błędu 404 i blokowanie adresów IP

Własna strona błędu to jedna linijka:

ErrorDocument 404 /404.html

Podawajcie ścieżkę lokalną, nie pełny adres z https://. Przy pełnym adresie Apache wysyła przekierowanie zamiast kodu 404, co według dokumentacji Apache myli roboty (także roboty wyszukiwarek) sprawdzające po kodzie odpowiedzi, czy adres istnieje. W WordPressie stronę 404 obsługuje motyw, więc ta dyrektywa zwykle nie jest potrzebna.

Blokowanie adresów IP w Apache 2.4 (stara składnia Deny from pochodzi z wersji 2.2):

<RequireAll>
  Require all granted
  Require not ip 203.0.113.15
</RequireAll>

Do dyrektyw Require w pliku .htaccess potrzebne jest AllowOverride AuthConfig.

Blokowanie botów: najpierw sprawdźcie, kogo blokujecie

Przez .htaccess można odciąć bota po nazwie z nagłówka User-Agent, zwracając mu kod 403:

RewriteCond %{HTTP_USER_AGENT} GPTBot [NC]
RewriteRule ^ - [F]

Zanim to zrobicie, sprawdźcie w dokumentacji operatora, do czego bot służy. OpenAI rozdziela trzy agenty: GPTBot zbiera dane do trenowania modeli, OAI-SearchBot służy do pokazywania stron w wynikach wyszukiwania ChatGPT, a ChatGPT-User działa przy akcjach wywołanych przez użytkownika. Według OpenAI każde z tych ustawień jest niezależne. Zablokowanie GPTBot nie usuwa strony z wyszukiwania ChatGPT, zablokowanie OAI-SearchBot już tak. Jeśli zależy wam na widoczności w odpowiedziach generowanych przez AI, blokujcie selektywnie.

Trzy karty botów OpenAI. GPTBot zbiera dane do trenowania modeli, a jego blokada nie zmienia widoczności w wyszukiwaniu ChatGPT. OAI-SearchBot pokazuje strony w wynikach wyszukiwania ChatGPT, a jego blokada usuwa stronę z tych wyników. ChatGPT-User obsługuje akcje wywołane przez użytkownika i nie skanuje sieci automatycznie

Rys. 4. Blokada „botów AI” jednym wpisem odcina też wyszukiwanie w ChatGPT, a tego zwykle nikt nie chce.

Do botów, które przestrzegają reguł, wystarczy robots.txt. Blokada w .htaccess ma sens wobec scraperów, które robots.txt ignorują.

Migracja serwisu: kiedy .htaccess przestaje wystarczać

Przy zmianie domeny albo struktury adresów pojedyncze reguły z tego tekstu składają się w mapę przekierowań: stary adres, nowy adres, kod. Jak ją przygotować i jak długo utrzymywać przekierowania, opisujemy w tekście o przekierowaniu strony i domeny.

Od strony pliku jedna uwaga: przy kilkuset regułach zawartość pliku .htaccess robi się nieczytelna, a serwer czyta go przy każdym żądaniu. Wtedy lepiej przenieść mapę do konfiguracji serwera albo obsłużyć przekierowania w CMS-ie. Przy większym serwisie pozycjonowanie stron zaczyna się właśnie od tej mapy, a nie od nowych treści.

Błąd 500 i pętle przekierowań - jak je naprawić?

Błąd 500 Internal Server Error po zmianie pliku .htaccess to zwykle jedno z trzech: literówka w dyrektywie, dyrektywa niedozwolona przez AllowOverride albo dyrektywa modułu, który nie jest załadowany. Pętla przekierowań (ERR_TOO_MANY_REDIRECTS w Chrome) oznacza, że adres docelowy znowu spełnia warunek przekierowania.

Krok Co zrobić Czego szukać
1. Wyłączenie pliku Zmienić nazwę na .htaccess_backup i odświeżyć stronę Jeśli 500 znika, przyczyna jest w pliku
2. Log błędów Otworzyć error_log w panelu hostingu Komunikat wskazuje plik i dyrektywę, np. RewriteCond: bad flag delimiters
3. Uprawnienia Sprawdzić AllowOverride w konfiguracji serwera „not allowed here” oznacza dyrektywę spoza dozwolonych grup
4. Łańcuch przekierowań curl -sIL http://example.pl/adres Każdy skok z kodem i nagłówkiem Location, pętla widoczna od razu
5. Konflikty reguł Porównać reguły pliku, CMS i proxy Wymuszanie i usuwanie www albo ukośnika naraz, %{HTTPS} za proxy

Polecenie curl -sIL pobiera tylko nagłówki i podąża za przekierowaniami, więc pokazuje cały łańcuch. Testujcie w terminalu albo w oknie prywatnym. Przeglądarki zapamiętują przekierowania 301 i po poprawce mogą dalej pokazywać stary wynik.

Okno terminala z wynikiem polecenia curl -sIL dla http://www.example.pl/stary-adres: trzy odpowiedzi 301 z nagłówkami Location, kolejno na HTTPS, na wersję bez www i na nowy adres, a na końcu odpowiedź 200. Obok opis każdego skoku

Rys. 5. Trzy skoki w jednym łańcuchu. Pierwsze dwa znikną po połączeniu reguł HTTPS i www w jedną.

O <IfModule mod_rewrite.c> wokół przekierowań: blok chroni przed błędem 500, gdy moduł nie jest załadowany, ale wtedy przekierowania po cichu przestają działać i nikt tego nie zauważa. Naszym zdaniem przy przekierowaniach SEO lepiej dostać błąd 500 od razu po wdrożeniu niż po kilku tygodniach odkryć w Search Console, że stare adresy zwracają 200.

Najczęstsze pytania o plik .htaccess

1. Gdzie znajduje się plik .htaccess?

Zwykle w katalogu głównym strony, czyli w public_html, www albo htdocs na serwerze. Nazwa zaczyna się od kropki, więc w menedżerze plików i kliencie FTP trzeba włączyć wyświetlanie plików ukrytych. Jeśli pliku nie ma, można go utworzyć jako zwykły plik tekstowy.

2. Czy plik .htaccess działa na serwerze Nginx?

Nie. Nginx nie czyta plików .htaccess, a przekierowania trzeba ustawić w konfiguracji serwera, w składni Nginx. Reguły z Apache nie przenoszą się jeden do jednego.

3. Dlaczego zmiany w pliku .htaccess nie działają?

Zwykle z jednego z trzech powodów: serwer ignoruje plik (AllowOverride None), wzorzec zaczyna się od ^/ albo reguła stoi pod blokiem CMS-u. Sprawdźcie też, czy nie testujecie w przeglądarce, która zapamiętała wcześniejsze przekierowanie 301.

4. Czy kolejność reguł w .htaccess ma znaczenie?

Tak. Reguły mod_rewrite są przetwarzane od góry, a pierwsza pasująca reguła z flagą L kończy przebieg. Kanonizację domeny dajcie na samą górę, potem przekierowania pojedynczych adresów, na końcu blok CMS-u.

5. Jak naprawić błąd „Strona spowodowała zbyt wiele przekierowań”?

Trzeba znaleźć dwie reguły, które odsyłają do siebie nawzajem. Typowe przyczyny to wymuszanie i usuwanie www albo ukośnika jednocześnie (na przykład reguła w .htaccess i ustawienie CMS-u) albo przekierowanie na HTTPS za Cloudflare w trybie „Flexible”. curl -sIL pokaże, między którymi adresami krąży żądanie.

6. Jak zrobić przekierowanie 301 w pliku .htaccess?

Jeśli chcecie przenieść jedną podstronę na inny adres, wystarczy jedna linia: Redirect 301 /stary-adres/ https://example.pl/nowy-adres/ albo reguła RewriteRule ^stary-adres/?$ /nowy-adres/ [R=301,L]. Pierwsza przekierowuje też wszystko, co leży pod starą ścieżką, druga tylko ten jeden adres. Obie wpisujcie nad blokiem CMS-u.

Źródła

Wszystkie źródła sprawdzone 15 października 2026.