Jak działa .htaccess
Plik .htaccess zmienia ustawienia serwera Apache dla katalogu strony, nawet gdy nie masz dostępu do konfiguracji serwera. Kiedy Apache go czyta, co może zawierać, jak się go pisze i dlaczego jedna literówka unieruchamia całą stronę błędem 500.
Czym jest .htaccess
.htaccess to zwykły plik tekstowy z dyrektywami (poleceniami) dla serwera Apache. Obowiązuje w katalogu, w którym leży, i we wszystkich jego podkatalogach. Apache czyta go przy każdym żądaniu, więc zmiana działa od razu po zapisaniu pliku – serwera się nie restartuje. Przydaje się tam, gdzie nie masz dostępu do konfiguracji serwera, typowo na hostingu współdzielonym.
Nazwa brzmi dokładnie .htaccess – z kropką na początku i bez rozszerzenia. Pliki zaczynające się kropką są w Linuksie ukryte, dlatego niektóre programy FTP i menedżery plików pokażą je dopiero wtedy, gdy w ich ustawieniach włączysz wyświetlanie ukrytych plików.
Gdzie działa .htaccess
- Apache czyta plik, jeśli pozwala na to konfiguracja serwera (dyrektywa AllowOverride niżej). Czyta go też zgodny z Apache serwer LiteSpeed.
- nginx nie zna pliku .htaccess. Reguły są bezpośrednio w konfiguracji serwera, na hostingu zwykle ustawiane przez jego panel.
- Dostawcy hostingu często stawiają nginx przed Apache. Wtedy zależy, kto wysyła pliki statyczne: jeśli obrazy, style i skrypty wysyła bezpośrednio nginx, reguły z .htaccess ich nie dotyczą (na przykład nagłówki pamięci podręcznej). Strony PHP przetwarza Apache, więc ich reguły dotyczą. Jak jest na twojej stronie, pokaże sprawdzenie nagłówków na końcu artykułu.
AllowOverride: co wolno plikowi .htaccess
W konfiguracji serwera dyrektywa AllowOverride decyduje, które grupy dyrektyw .htaccess może zmieniać w danym katalogu. W Apache 2.4 wartością domyślną jest None – plik .htaccess w ogóle nie jest czytany, nawet jeśli zawiera błąd. Dostawcy hostingu zwykle pozwalają na wszystko (All). Na własnym serwerze albo w lokalnym środowisku programistycznym ustawia się to w konfiguracji strony:
<Directory "/var/www/example.com"> AllowOverride All </Directory>
Zamiast All można wymienić tylko niektóre grupy:
- FileInfo – przekierowania i mod_rewrite (Redirect, RewriteRule), nagłówki (Header), strony błędów (ErrorDocument), typy plików i kodowania (AddType, AddDefaultCharset);
- AuthConfig – dostęp i hasła (Require, AuthType, AuthUserFile);
- Indexes – plik domyślny katalogu (DirectoryIndex, FallbackResource) i pamięć podręczna z mod_expires (ExpiresActive, ExpiresByType);
- Options – dyrektywa Options (na przykład wyłączenie listy zawartości katalogu).
Dyrektywa z niedozwolonej grupy kończy się błędem 500, a w dzienniku błędów serwera pojawia się komunikat w rodzaju Require not allowed here.
Jak pisze się .htaccess
- jedna dyrektywa w wierszu, jej parametry oddzielone spacjami; parametr ze spacją ujmuje się w cudzysłów;
- w nazwach dyrektyw wielkość liter nie ma znaczenia (RewriteEngine i rewriteengine), w ścieżkach i nazwach plików na serwerze z Linuksem ma;
- wiersz zaczynający się znakiem # jest komentarzem;
- bloki takie jak <IfModule> czy <FilesMatch> otwiera się i zamyka podobnie jak znaczniki HTML.
# Plik domyślny katalogu: najpierw index.php, potem index.html DirectoryIndex index.php index.html # Własna strona dla adresów, które nie istnieją ErrorDocument 404 /404.php
Komentarz nie może stać w tym samym wierszu za dyrektywą. Apache go nie rozpozna i uzna za kolejne parametry. Ten wiersz kończy się więc błędem 500, a w dzienniku pojawi się Header has too many arguments:
Header set X-Robots-Tag "noindex" # poza wyszukiwarkami
Gorzej jest z dyrektywami, które przyjmują dowolną liczbę parametrów. DirectoryIndex index.php # domyślny nie spowoduje błędu 500, ale po cichu weźmie znak # i słowo za nim jako kolejne nazwy plików – gdy brakuje index.php, Apache szuka plików „#” i „domyślny”.
Zapisz plik w kodowaniu UTF-8. Końce wierszy mogą być windowsowe albo linuksowe, a niewidoczny znak BOM na początku pliku Apache 2.4 pomija.
Błąd 500: jedna literówka unieruchamia cały katalog
Nieznana dyrektywa albo błędny zapis sprawia, że Apache odrzuca cały plik. Każde żądanie do katalogu i wszystkich jego podkatalogów kończy się wtedy błędem 500 Internal Server Error – przy .htaccess w katalogu głównym strony to cała strona. Na przyczynę wskazuje dziennik błędów serwera (na hostingu zwykle w panelu). Przy literówce RewriteEngin On jest w nim (bez daty i numeru procesu):
[core:alert] [client 203.0.113.5:52814] /var/www/example.com/.htaccess: Invalid command 'RewriteEngin', perhaps misspelled or defined by a module not included in the server configuration
Ten sam komunikat pojawi się przy poprawnie zapisanej dyrektywie modułu, który na serwerze nie jest włączony. Ustawienia dla opcjonalnych modułów otacza się dlatego blokiem <IfModule> – gdy modułu brak, Apache pomija zawartość bloku:
<IfModule mod_expires.c> ExpiresActive On ExpiresDefault "access plus 1 hour" </IfModule>
W <IfModule> moduł można podać nazwą jego pliku źródłowego (mod_expires.c) albo nazwą modułu (expires_module). Uwaga: gdy modułu brak, ustawienia po cichu nie zostaną zastosowane. Po wgraniu pliku sprawdź więc, czy działają – na przykład nagłówkami pokazanymi na końcu tego artykułu.
Zanim zmienisz plik na stronie produkcyjnej, zapisz jego działającą wersję. Jeśli po wgraniu strona zgłosi błąd 500, przywrócisz ją w kilka sekund.
Podkatalogi
Podkatalog może mieć własny .htaccess. Ustawienia z katalogów nadrzędnych obowiązują w nim nadal, a jego własny plik je uzupełnia albo nadpisuje. Na przykład w katalogu głównym strony:
AddDefaultCharset UTF-8
i w katalogu archive ze starszymi stronami:
AddDefaultCharset windows-1252
Strony HTML są wtedy wszędzie wysyłane z kodowaniem UTF-8, tylko w katalogu archive i jego podkatalogach z windows-1252. Wyjątkiem są reguły mod_rewrite: gdy podkatalog włączy własne RewriteEngine On, reguły katalogu nadrzędnego przestają w nim obowiązywać (zobacz mod_rewrite i przyjazne adresy URL).
Wydajność
Gdy pliki .htaccess są dozwolone, Apache przy każdym żądaniu szuka ich we wszystkich katalogach na drodze do pliku – przy adresie /articles/2026/photo.jpg w katalogu głównym strony, w katalogu articles i w katalogu 2026 – i znalezione czyta za każdym razem od nowa. Na zwykłej stronie tego nie widać. Kto ma dostęp do konfiguracji serwera, może jednak przenieść reguły tam i wyłączyć .htaccess (AllowOverride None), jak opisuje Szukanie błędów w .htaccess i konfiguracji serwera.
Jak sprawdzić wynik
Najszybciej zobaczysz, co wysyła serwer, poleceniem curl (jest częścią Windows 10 i 11, a w Linuksie i macOS zwykle też jest dostępne). Parametr -I wypisze tylko nagłówki odpowiedzi:
curl -I https://www.example.com/
Pierwszy wiersz to kod statusu (HTTP/1.1 200 OK, przy HTTP/2 tylko HTTP/2 200), pod nim są nagłówki – na przykład Location przy przekierowaniu albo Content-Type z typem pliku. Parametr -I wysyła żądanie HEAD: skrypt PHP wykona się w całości, serwer tylko nie wyśle treści odpowiedzi. To samo pokaże karta Network w narzędziach deweloperskich przeglądarki (F12).
Powiązane artykuły:
Nagłówki bezpieczeństwa i HTTPS
Przekierowania w .htaccess: 301, 302 i jeden adres strony
Szukanie błędów w .htaccess i konfiguracji serwera
Komunikaty o błędach na stronie produkcyjnej