icomHOST

Wszystko o domenach i hostingach

HTACCESS – najważniejsze komendy

HTACCESS – najważniejsze komendy

Plik .htaccess to kieszonkowy panel sterowania dla hostingu na serwerze Apache (oraz kompatybilnych, jak LiteSpeed). Pozwala bez dostępu do głównej konfiguracji wykonywać zmiany blisko aplikacji: wymuszać szyfrowanie, definiować reguły URL, optymalizować dostarczanie statycznych plików i wzmacniać bezpieczeństwo. Dla większości projektów na współdzielonych planach hostingowych to najpraktyczniejszy sposób na szybkie wdrażanie zasad, które normalnie wymagałyby uprawnień administratora. Poniżej znajdziesz przewodnik po najważniejszych komendach i wzorcach wraz z kontekstem serwerowym, typowymi pułapkami i gotowymi fragmentami do użycia w produkcji.

.htaccess w kontekście hostingu: jak działa i gdzie ma sens

.htaccess działa w tzw. kontekście katalogowym: Apache przetwarza go dla bieżącego katalogu i wszystkich jego podkatalogów. To oznacza, że reguły umieszczone w katalogu głównym witryny kształtują zachowanie całości strony, a reguły w katalogu /assets dotyczą wyłącznie zasobów w /assets. Na hostingu współdzielonym to silny atut, bo nie potrzebujesz uprawnień root, by wprowadzać zmiany – wystarczy dostęp FTP lub menedżer plików w panelu administracyjnym. Z kolei na serwerach dedykowanych i VPS wydajniej jest umieszczać reguły w globalnej konfiguracji VirtualHost (Directives in server config), bo .htaccess jest parsowany przy każdym żądaniu, co bywa kosztowne.

Warto też znać różnice platform: Apache obsługuje .htaccess natywnie, LiteSpeed i OpenLiteSpeed w dużej mierze są z nim zgodne, Nginx natomiast nie wspiera .htaccess w ogóle (wymaga własnych reguł w nginx.conf). Dlatego migracje między hostingami mogą pociągać za sobą przepisywanie reguł. Jeżeli Twój operator hostingu korzysta z LiteSpeed, większość przykładów zadziała bez zmian, ale niektóre moduły (np. ekscentryczne dyrektywy logowania) mogą się różnić.

Do aktywacji możliwości .htaccess na poziomie Apache potrzebne jest AllowOverride w konfiguracji katalogu (np. AllowOverride All). Na hostingu masz to zwykle włączone. Jeśli jakaś dyrektywa nie działa, możliwe, że jest zablokowana przez dostawcę (dla bezpieczeństwa) albo moduł nie jest załadowany.

Składnia, porządek i minimalne dobre praktyki

Składnia .htaccess jest linia-po-linii: puste linie i linie zaczynające się od # to komentarze. Kolejność ma znaczenie – szczególnie przy regułach mod_rewrite i dopasowaniach wzorców. Podstawowe reguły:

  • # Komentarz – dokumentuj, do czego służy dana sekcja i kiedy została dodana
  • Options -Indexes – wyłącza listing plików w katalogu
  • DirectoryIndex index.php index.html – kontrola strony startowej
  • FileETag None – redukcja złożoności ETagów na niektórych hostingach
  • ServerSignature Off – usuwa sygnaturę serwera z błędów

Przetwarzanie per katalog oznacza, że Apache stosuje reguły nałożone hierarchicznie. W przypadku przepisywania adresów (RewriteRule) pamiętaj, że w .htaccess reguły działają z „przyciętym” prefiksem katalogu, a nie od root-a systemu plików. Gdy aplikacja leży w podkatalogu, potrzebny bywa RewriteBase, aby poprawnie zbudować ścieżki względne.

Zanim przejdziesz do złożonych wzorców, uporządkuj strukturę: sekcja dla wydajność (kompresja i caching), sekcja dla przekierowania (kanoniczny host, HTTP→HTTPS), sekcja dla ochrony (blokady, nagłówki), a na końcu reguły aplikacji (front controller, statyki). Wyraźny podział ułatwia utrzymanie i audyt bezpieczeństwa.

Najważniejsze przepisy URL z modułem mod_rewrite

Sercem przyjaznych URL i przekierowań jest moduł mod_rewrite. Aktywacja i podstawowe idiomy:

  • RewriteEngine On – włącz moduł przepisywania
  • RewriteBase / – ustaw bazę (gdy aplikacja jest w katalogu głównym)
  • RewriteCond %{REQUEST_FILENAME} !-f – warunek: nie istnieje plik
  • RewriteCond %{REQUEST_FILENAME} !-d – warunek: nie istnieje katalog
  • RewriteRule ^blog/([0-9]+)/?$ wpis.php?id=$1 [L,QSA] – przykładowe przepisywanie

Najczęstsze flagi:

  • L – „last”: kończy dalsze reguły w bieżącym kontekście
  • R=301 – stałe przekierowanie (uwaga na cache przeglądarek podczas testów)
  • QSA – dołącz parametry zapytania (query string append)
  • NC – dopasowanie bez rozróżniania wielkości liter
  • END – kończy wszystkie dalsze przepisywania (Apache 2.4+, szerzej niż L)
  • QSD – odrzuca istniejący query string

Typowe zadania i gotowe fragmenty zamienione na listy dla czytelności:

  • Usuwanie końcowego ukośnika: RewriteRule ^(.+?)/?$ /$1 [R=301,L]
  • Dodawanie końcowego ukośnika: RewriteCond %{REQUEST_URI} !/$ [NC] + RewriteRule ^ %{REQUEST_URI}/ [R=301,L]
  • Usuwanie „index.php” z adresu: RewriteRule ^index.php$ / [R=301,L]
  • Front controller (np. framework): RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_FILENAME} !-d + RewriteRule . index.php [L]
  • Przekierowanie starego katalogu: RewriteRule ^old/(.*) /new/$1 [R=301,L]
  • Obsługa wersji API: RewriteRule ^api/v([0-9]+)/users$ api/users.php?version=$1 [L,QSA]

Uwaga na MultiViews: włączona opcja treści negocjowanych (Options MultiViews) potrafi zaskakująco „zgadywać” pliki i kolidować z regułami rewrite. Najczęściej warto ją wyłączyć: Options -MultiViews.

Diagnostyka rewritów: testuj na R=302 (tymczasowe) zanim utrwalisz R=301, bo przeglądarki i proxy agresywnie zapamiętują 301. Jeśli masz dostęp do logów, szukaj linii „rewrite” – wiele hostingów LiteSpeed/Apache zapisuje ślady reguł. W trudnych przypadkach dodawaj warunkowe blokady, np. ignoruj panel administracyjny: RewriteRule ^admin/ – [L].

HTTPS, host kanoniczny i kolejność reguł

Kwestie adresacji warto rozwiązać w stały sposób: wymuś HTTPS, ustal jedną wersję hosta (www lub bez www), a dopiero potem obsługuj pozostałe przekierowania aplikacyjne. Kolejność ma znaczenie, żeby nie powstawały pętle i podwójne przeskoki.

Minimalny zestaw dla kanonicznego hosta bez www z jednoczesnym HTTPS:

  • RewriteEngine On
  • RewriteCond %{HTTPS} !=on [OR]
  • RewriteCond %{HTTP_HOST} ^www.(.+)$ [NC]
  • RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L]

Wersja „z www”:

  • RewriteEngine On
  • RewriteCond %{HTTPS} !=on [OR]
  • RewriteCond %{HTTP_HOST} !^www. [NC]
  • RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

Dla aplikacji w podkatalogu dodaj RewriteBase i buduj adresy względne ostrożnie. W kontekście SEO i kanonizacja adresów warto, by każde źródło treści wskazywało na pojedynczy URL – unikniesz rozcieńczania sygnałów rankingowych.

HSTS (Strict-Transport-Security) można wymusić przez nagłówek: Header always set Strict-Transport-Security „max-age=31536000; includeSubDomains; preload”. To potężny mechanizm – po wdrożeniu odwiedzający nie będą mogli używać HTTP przez czas max-age. Testuj najpierw na mniejszym oknie czasowym, bo błąd w certyfikacie zablokuje dostęp.

Wydajność: kompresja i cache zasobów

Transport mniejszych i rzadziej odświeżanych plików to podstawa rychłego TTFB i szybkich metryk Core Web Vitals. Na hostingu Apache robi się to dwutorowo: włącza się kompresja transferu i kontroluje politykę buforowania cache.

Kompresja HTML, CSS, JS

Jeżeli masz mod_deflate i/lub mod_brotli, włącz filtr dla typów treści:

  • # Gzip (mod_deflate): AddOutputFilterByType DEFLATE text/html text/plain text/css application/javascript application/json image/svg+xml
  • # Brotli (mod_brotli): AddOutputFilterByType BROTLI_COMPRESS text/html text/plain text/css application/javascript application/json image/svg+xml
  • SetEnvIfNoCase Request_URI .(?:gif|jpe?g|png|mp4|avi|webp|woff2?)$ no-gzip dont-vary – nie kompresuj binariów

W praktyce Brotli daje lepszy ratio niż gzip, ale nie każdy hosting ma go włączony. Możesz utrzymać oba, serwer sam dobierze możliwą metodę negocjacją Accept-Encoding.

Cache-Control i Expires

Statyki warto cache’ować długo (z wersjonowaniem w nazwie pliku), a HTML – krótko lub wcale. Przykładowa polityka:

  • ExpiresActive On
  • # Długie cache dla wersjonowanych plików
  • ExpiresByType image/jpeg „access plus 1 year”
  • ExpiresByType image/png „access plus 1 year”
  • ExpiresByType image/webp „access plus 1 year”
  • ExpiresByType text/css „access plus 1 year”
  • ExpiresByType application/javascript „access plus 1 year”
  • # Krótkie dla HTML
  • ExpiresByType text/html „access plus 0 seconds”
  • Header set Cache-Control „public, max-age=31536000, immutable” „expr=%{resp:Content-Type} =~ m#(text/css|application/javascript|image/|font/)#”
  • Header set Cache-Control „no-store, no-cache, must-revalidate” „expr=%{resp:Content-Type} = 'text/html'”

ETag bywa problematyczny na klastrach (różne inode), dlatego często lepiej go wyłączyć i polegać na Last-Modified oraz Cache-Control. Wersjonowanie nazw (style.20240214.css) eliminuje ryzyko serwowania starych zasobów z cache po wdrożeniu.

Warstwa bezpieczeństwa: blokady, nagłówki i strefy zaufania

Większość incydentów na hostingu to nie „wielkie” luki, lecz drobne zaniedbania: listing katalogów, wykonywalne pliki w uploadach, brak zasad dla iframes. W .htaccess możesz wprowadzić szybkie bariery, które istotnie wzmacniają bezpieczeństwo.

Wyłączenie listingu i egzekucji w katalogach wrażliwych

  • Options -Indexes – brak listy plików, gdy nie ma index.*
  • # katalog uploads – zablokuj wykonywanie PHP
  • Umieść w /uploads/.htaccess:
  • RemoveHandler .php .phtml .php3 .php4 .php5 .php7
  • php_flag engine off – działa tylko przy mod_php; na PHP-FPM użyj blokady handlerów

Ochrona hasłem i po adresie IP

  • AuthType Basic
  • AuthName Strefa chroniona
  • AuthUserFile /ścieżka/poza/www/.htpasswd
  • Require valid-user
  • # lub
  • Require ip 203.0.113.0/24

Stosuj to dla paneli administracyjnych i narzędzi deweloperskich. Wersja IP jest bezobsługowa i bardzo skuteczna, ale wymaga stałego adresu.

Nagłówki bezpieczeństwa

Jeśli mod_headers jest dostępny, ustawiaj podstawowe nagłówki defensywne:

  • Header always set X-Frame-Options „SAMEORIGIN”
  • Header always set X-Content-Type-Options „nosniff”
  • Header always set Referrer-Policy „strict-origin-when-cross-origin”
  • Header always set Permissions-Policy „geolocation=(), microphone=(), camera=()”
  • # CSP wymaga testów – zacznij od trybu report-only w fazie wdrożenia
  • Header set Content-Security-Policy-Report-Only „default-src 'self'”

Blokada hotlinkingu

  • RewriteEngine On
  • RewriteCond %{HTTP_REFERER} !^$
  • RewriteCond %{HTTP_REFERER} !example.com [NC]
  • RewriteCond %{HTTP_REFERER} !example.pl [NC]
  • RewriteRule .(jpe?g|png|gif|webp)$ – [F]

Zamiast odrzucać, możesz zwracać lekki placeholder, np. /img/nohotlink.png, by oszczędzić transfer.

Strony błędów, tryb serwisowy i ergonomia utrzymania

Własne strony błędów wyglądają profesjonalnie i potrafią utrzymać użytkownika na stronie mimo kłopotów. Do tego .htaccess bywa wygodną dźwignią „maintenance mode”.

  • ErrorDocument 404 /404.html
  • ErrorDocument 500 /500.html
  • # Tryb serwisowy: jeśli plik .maintenance istnieje, podaj maintenance.html
  • RewriteCond %{DOCUMENT_ROOT}/.maintenance -f
  • RewriteCond %{REQUEST_URI} !^/maintenance.html$
  • RewriteRule ^ /maintenance.html [R=302,L]

Rozsądnie jest dopuścić swój adres IP, aby móc sprawdzać produkcję podczas prac:

  • RewriteCond %{REMOTE_ADDR} !^203.0.113.45$

CORS, typy MIME, czcionki i API

Nowoczesne frontendy i CDN-y często wymagają doprecyzowania typów MIME i polityki CORS. Błędny MIME dla WOFF2 powoduje, że przeglądarka odrzuca fonty; zbyt luźny CORS otwiera niepotrzebnie interfejs API.

  • AddType font/woff2 .woff2
  • AddType image/svg+xml .svg
  • AddDefaultCharset UTF-8
  • # CORS: tylko dla API
  • W katalogu /api:
  • Header always set Access-Control-Allow-Origin „https://app.example.com”
  • Header always set Access-Control-Allow-Methods „GET, POST, OPTIONS”
  • Header always set Access-Control-Allow-Headers „Content-Type, Authorization”
  • Header always set Access-Control-Max-Age „86400”

Jeżeli serwujesz fonty z innej domeny (CDN), dopisz odpowiedni Access-Control-Allow-Origin dla ich lokalizacji, inaczej przeglądarki zablokują je jako cross-origin bez autoryzacji.

CMS i frameworki: wzorce reguł i typowe kolizje

WordPress, Drupal, Laravel czy Symfony polegają na front controllerze index.php. Ich domyślne .htaccess potrafią kolidować z dodatkowymi regułami właściciela serwisu, zwłaszcza gdy dotyczą przekierowań kanonicznych. Najbezpieczniej jest trzymać reguły hosta/HTTPS nad blokiem generowanym przez CMS i nie modyfikować sekcji, którą system nadpisuje automatycznie.

Przykład minimalny dla WordPress:

  • RewriteEngine On
  • RewriteBase /
  • RewriteRule ^index.php$ – [L]
  • RewriteCond %{REQUEST_FILENAME} !-f
  • RewriteCond %{REQUEST_FILENAME} !-d
  • RewriteRule . /index.php [L]

Laravel/Symfony (public/ jako webroot): jeśli aplikacja jest wdrożona w /public, ustaw DocumentRoot w panelu hostingu; gdy to niemożliwe, przepuść żądania do public/ przez rewrite i zablokuj dostęp do plików wrażliwych (env, yaml). Przykład uproszczony:

  • RewriteEngine On
  • RewriteRule ^$ public/ [L]
  • RewriteRule (.*) public/$1 [L]
  • <pliki do ukrycia> – użyj FilesMatch: FilesMatch „.(env|ya?ml|lock)$” → Require all denied

Typowe kolizje: włączony MultiViews, podwójne przekierowanie www↔bez www, reguły HSTS tylko na części hostów, nieprzemyślany QSD usuwający parametry płatności. Zawsze testuj ścieżki płatności, callbacki bramek i webhooki.

Różnice serwerowe, moduły i ograniczenia hostingu

Wiele dyrektyw .htaccess działa tylko wtedy, gdy moduł jest załadowany: mod_rewrite, mod_headers, mod_expires, mod_deflate, mod_brotli. Na współdzielonym hostingu zwykle nie zobaczysz listy loaded modules – sprawdź dokumentację operatora albo eksperymentuj bezpiecznie. Brak wsparcia objawi się błędem 500 po dodaniu nieznanej dyrektywy. Wtedy skomentuj linię i zapytaj support o dostępność modułu.

PHP: dyrektywy php_value/php_flag działają wyłącznie przy mod_php. Coraz więcej hostingów używa PHP-FPM, gdzie ustawień dokonuje się w .user.ini albo w panelu. Jeśli dodasz php_value memory_limit 512M w .htaccess i dostaniesz 500, prawdopodobnie używasz FPM – przenieś ustawienia do .user.ini (memory_limit=512M).

LiteSpeed: kompatybilny z większością reguł Apache, często szybciej interpretuje rewrit-y i ma własne mechanizmy cache (LSCache), które mogą współgrać z .htaccess przez specjalne dyrektywy. Jeżeli używasz wtyczki LSCache, nie duplikuj reguł Expires/Cache-Control – zrobisz sprzeczne nagłówki.

Nginx: ignoruje .htaccess. Przy migracji przepisz reguły do bloku server/location. Dotyczy to zwłaszcza przepisów WordPress i kanonicznych przekierowań. Po stronie Nginx wydajność bywa lepsza, bo konfiguracja jest parsowana raz przy starcie, nie przy każdym żądaniu.

Diagnostyka i bezpieczne wdrożenia

Podstawowe zasady wdrożenia to: małe kroki, szybki rollback i testy w wielu przeglądarkach. Zanim wstawisz R=301, używaj R=302. Utrzymuj kopię poprzedniej wersji .htaccess (np. .htaccess.bak). Po zmianach wyczyść pamięć podręczną przeglądarki i sprawdź zachowanie w trybie prywatnym, bo polityki cache mogą maskować błędy.

Żeby zrozumieć dopasowania, ogranicz reguły do minimalnych warunków i testuj pojedynczo. W rewritach preferuj kotwiczenie (^ i $), unikaj zbyt agresywnych .*, używaj grupowania (?: ) dla fragmentów bez przechwytywania. Pamiętaj, że L kończy przetwarzanie w bieżącym kontekście; gdy masz wiele warstw (katalogi), rozważ END.

Checklist utrzymaniowy dla pliku .htaccess

  • Masz włączone wymuszanie HTTPS i ustalony kanoniczny host?
  • Czy Options -Indexes jest aktywne wszędzie, gdzie nie serwujesz list?
  • Czy statyczne pliki mają długie cache i wersjonowane nazwy?
  • Czy kompresja (gzip/Brotli) działa dla HTML/CSS/JS?
  • Czy fonty i SVG mają właściwy typ MIME?
  • Czy panel admina jest dodatkowo osłonięty (IP/hasło)?
  • Czy webhooki i bramki płatności nie tracą parametrów po przekierowaniach?
  • Czy reguły rewritów nie tworzą pętli (sprawdź www↔bez www)?
  • Czy masz przygotowany tryb serwisowy i wykluczenie IP dewelopera?
  • Czy nie mieszasz sprzecznych nagłówków cache (LSCache vs Expires)?

Przykładowy szkielet produkcyjnego .htaccess

Poniższy szkielet można dostosować do większości serwisów na Apache/LiteSpeed:

  • # 1) Twarde zasady serwera
  • ServerSignature Off
  • Options -Indexes -MultiViews
  • DirectoryIndex index.php index.html
  • # 2) HTTPS i host
  • RewriteEngine On
  • RewriteCond %{HTTPS} !=on [OR]
  • RewriteCond %{HTTP_HOST} ^www.(.+)$ [NC]
  • RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L]
  • # 3) Bezpieczeństwo nagłówków
  • Header always set X-Frame-Options „SAMEORIGIN”
  • Header always set X-Content-Type-Options „nosniff”
  • Header always set Referrer-Policy „strict-origin-when-cross-origin”
  • # 4) Kompresja i cache
  • AddOutputFilterByType DEFLATE text/html text/plain text/css application/javascript image/svg+xml
  • ExpiresActive On
  • ExpiresByType text/html „access plus 0 seconds”
  • ExpiresByType text/css „access plus 1 year”
  • ExpiresByType application/javascript „access plus 1 year”
  • ExpiresByType image/webp „access plus 1 year”
  • # 5) MIME
  • AddType font/woff2 .woff2
  • AddType image/svg+xml .svg
  • # 6) Reguły aplikacji
  • RewriteRule ^index.php$ – [L]
  • RewriteCond %{REQUEST_FILENAME} !-f
  • RewriteCond %{REQUEST_FILENAME} !-d
  • RewriteRule . index.php [L]
  • # 7) Błędy
  • ErrorDocument 404 /404.html
  • ErrorDocument 500 /500.html

Po wdrożeniu powyższego szkieletu uzupełnij go o specyfikę projektu: dodatkowe blokady, wykluczenia katalogów (np. dla panelu), politykę CORS oraz nietypowe przepisy URL wymagane przez aplikację.

Wpływ na SEO, CDN i logikę warstwy brzegowej

Zmiany w .htaccess oddziałują na sposób, w jaki roboty i klienci widzą witrynę. Ujednolicenie adresów, spójne 301, krótsze ścieżki i stabilne treści to twarde fundamenty pod SEO. Z kolei odpowiednie cache-control i ETag decydują o skuteczności CDN – pamiętaj, że CDN najpierw pobiera wersję „origin”, więc wszystkie nagłówki wysyłane przez serwer mają pierwszeństwo w kształtowaniu polityk brzegowych. Jeżeli CDN ma własne zasady, upewnij się, że nie nadpisujesz ich niechcący przeciwnymi dyrektywami, bo uzyskasz nieprzewidywalny efekt (np. stale przeterminowane zasoby).

Przy projektowaniu polityki cache uwzględnij różne typy klientów: przeglądarki mobilne, aplikacje natywne i roboty. Dla treści, które muszą się natychmiast odświeżać (koszyki, panel klienta), używaj no-store; dla zasobów publicznych – długich, immutable.

Typowe błędy i jak ich unikać

  • Testowanie z 301 – dopóki reguła nie jest pewna, używaj R=302, bo 301 zostaje w pamięci przeglądarki i utrudnia debugowanie.
  • Zbyt ogólne wzorce – .* bez kotwic prowadzi do zaskakujących dopasowań i pętli.
  • Mieszanie ładu reguł – najpierw host/HTTPS, potem reszta; w przeciwnym razie złapiesz łańcuch 2–3 przekierowań.
  • Niewyłączone MultiViews – potrafi „zgadywać” i nadpisywać przepisy URL.
  • Dyrektywy PHP w środowisku FPM – użyj .user.ini zamiast php_value/php_flag.
  • Brak wyjątków dla webhooków – upewnij się, że nie kasujesz query stringa (QSD) dla endpointów płatności.

Podsumowanie: jak z .htaccess zrobić przewagę, a nie kłopot

.htaccess, mądrze użyty, jest dźwignią, która pozwala skromnym nakładem pracy podnieść stabilność, bezpieczeństwo i szybkość serwisu na praktycznie każdym hostingu współdzielonym. Zacznij od porządków – ustal host i szyfrowanie, dodaj kompresję i długie cache zasobów, zastosuj podstawowe nagłówki bezpieczeństwa, a następnie dopracuj przepisy dla aplikacji. Rób zmiany iteracyjnie, dokumentuj i trzymaj porządek sekcji. Dzięki temu ten cienki plik stanie się spójną polityką usług webowych, zamiast zbiorem przypadkowych łatek.

Gdy projekt urośnie, przenieś cięższe reguły do konfiguracji wirtualnych hostów (na VPS/dedykowanym), a .htaccess pozostaw dla lokalnych wyjątków. Ta ewolucja zapewni Ci nie tylko przewidywalność zachowania, ale i mierzalne zyski wydajnościowe, które przełożą się bezpośrednio na komfort użytkownika i efektywność operacyjną zespołu.