Jakiś już czas temu pisałem jak przekierować ruch ze strony na serwerze Apache2, dziś – zgodnie z zapowiedzią – kolejna odsłona, tylko dla serwera opartego o Nginx…

W przypadku tego serwera (Nginx) nie mamy wprawdzie do dyspozycji pliku .htaccess, ale podobne efekty możemy uzyskać edytując plik konfiguracyjny danej strony (vHosta).

Nginx i przekierowania

Jeśli korzystacie z hostingu współdzielonego to najprawdopodobniej serwer to Apache2, i w takim przypadku odsyłam do tego artykułu/wpisu…

Jeśli korzystacie z własnego serwera to sami wybieracie z jakiego (web)serwera korzystacie, i jeśli to Apache2 – również odsyłam do tego poradnika. Jeśli wybraliście Nginx – to artykuł dla Was :-)

Więcej na temat konfiguracji serwera WWW opartego o Nginx pisałem tutaj…

R=301, R=302, R=307

Tak jak w przypadku poradnika dotyczącego przekierowań w Apache2 (.htaccess), tak i w tych przykładach mogą pojawiać 3 kody przekierowań:

  • R=301 – przekierowanie trwałe/stałe
  • R=302 – przekierowanie tymczasowe
  • R=307 – przerwa techniczna

Przekierowanie www.domena na domena

Chyba najczęściej prze zemnie wykorzystywane przekierowanie, które kieruje cały ruch bezpośrednio na domenę, z pominięciem „subdomeny” www:

# www.domena -> domena
server {
server_name www.[DOMENA];
return 301 $scheme://[DOMENA]$request_uri;
}

Ew. jakby ktoś chciał odwrotnie:

server {
server_name [DOMENA];
return 301 $scheme://www.[DOMENA]$request_uri;
}

Oczywiście podany wyżej kod (1 z 2) wstawiamy powyżej właściwego „server {„.

Wersja alternatywna:

location / {
if ($http_host ~ "^www.rembiejewski.pl$"){
rewrite ^/?$ /"http\:\/rembiejewski\.pl" redirect;
}
}

Lub prościej i chyba bardziej „OK”:

location / {
if ($host ~* ^www\.(.*)) {
return 301 $scheme://$http_host$request_uri;
}
}

Ten kod spowoduje przekierowanie każdego zapytania w postaci:

www.webinsider.pl/cokolwiek

na:

webinsider.pl/cokolwiek

Przekierowanie całego ruchu na inną domenę

By przekierować cały ruch z jednej domeny na inną – np. po zmianie adresu strony – wystarczy skorzystać z:

location / {
rewrite ^(.*)$ $scheme://nasza-nowa-domena.pl/$1 redirect;
}

Lub (zalecam):

location / {
return 301 $scheme://$http_host$request_uri;
}

Przekierowanie pojedynczego adresu URL

Możemy też przekierować pojedynczy adres URL:

location /stary-adres-url.htm {
rewrite ^(.*)$ http://jakaś-domena.pl/nowy-adres-url.htm redirect;
}

Przekierowanie „po slashu” (/)

Możemy ustawić przekierowanie „po slashu” dla naszej domeny:

location /poczta {
return 301 https://jakiś-serwer-pocztowy.pl/panel-poczty;
}

Spowoduje to, że po wpisaniu adresu:

http://jakaś-nasza-domena.pl/poczta

zostaniemy przekierowani na stronę:

https://jakiś-serwer-pocztowy.pl/panel-poczty

Warto też rozważyć dodanie znaku „=”, tak by przekierowanie dotyczyło tylko tego elementu (poczta), a nie wszystkiego co będzie zaczynać się od „poczta” (np. /poczta-jak-konigurowac):

location = /poczta {
return 301 https://jakiś-serwer-pocztowy.pl/panel-poczty;
}

Przekierowanie/zmiana typu pliku

location ~ (.*).html$ {
rewrite ^(.*)$ http://jakaś-nasza-domena.pl$1.php redirect;
}

I tym sposobem każde odwołanie do pliku HTML zostanie automatycznie zmienione na odwołanie do pliku PHP.

Podstawowe przykłady za nami, teraz kilka troszkę bardziej „skomplikowanych” scenariuszy:

Kilka domen, jeden katalog i jedna główna domena

Załóżmy, że mamy kilka domena:

  • nazwa-naszej-firmy.pl
  • nazwa-naszej-firmy.com.pl
  • nazwa-naszej-firmy.eu

I wszystkie 3 domeny kierują do tego samego katalogu na naszym serwerze, i tym samym wyświetlają tą samą stronę/zawartość, choć pod różnymi domenami.

I pewnie by tak mogło być, ale powiedzmy, że w ramach działań SEO (związanych z pozycjonowaniem strony) zapada decyzja by wszystkie domeny kierowały na główna, a przy okazji nie chcemy generować błędów 404 (nie znaleziono strony) jak ktoś skorzysta z linka do produktu/strony z jedną z alternatywnych domen.

W tym celu korzystamy z wpisu:

server {
server_name nazwa-naszej-firmy.pl nazwa-naszej-firmy.com nazwa-naszej-firmy.com.pl nazwa-naszej-firmy.com.pl nazwa-naszej-firmy.eu;
rewrite ^ http://nazwa-naszej-firmy.pl$request_uri? permanent;
}

Tym sposobem wszystkie adresy z domen innych niż .pl zostaną skierowane na nazwa-naszej-firmy.pl, czyli na główny adres.

Przerwa techniczna

Kolejny scenariusz to przerwa techniczna – chcemy wykonać kilka operacji (mniejszych lub większych ;-)) na stronie, będziemy pracować z konkretnych adresów IP… Pozostałych odwiedzających przekierujemy na przygotowaną w tym celu stronę informacyjna („Przepraszamy, przerwa techniczna. Zapraszamy o…”)

location / {
if (-f $document_root/przerwa_techniczna.html) {
return 503;
}
[STANDARDOWY KOD/PARAMETRY]
}
error_page 503 @maintenance;
location @maintenance {
if ($remote_addr !~ "^123.123.123.123"){
rewrite ^(.*)$ /przerwa_techniczna.html break;
}
}

Korzystamy tu z kilku „trików”:

Wykluczamy nasz adres IP z przekierowania, dzięki czemu sami będziemy mieli pełny dostęp do strony:

if ($remote_addr !~ "^123.123.123.123")

Zamiast 123.123.123.123 wstawcie swój adres IP.

Kolejny ważna linijka to:

if (-f $document_root/przerwa_techniczna.html)

Dzięki niej wykrywamy czy istnieje taki plik (przerwa_techniczna.html) na serwerze – jeśli tak, działa „przekierowanie serwisowe”, w innym wypadku strona działa normalnie.

Jest to o tyle wygodne, że w przypadku Nginx nie korzystamy z pliku .htaccess, a pliku konfiguracyjnego danej domeny (vHosta), i każda zmiana w nim wymaga restart serwera (Nginx, nie całego serwera ;-)) lub chociaż odświeżenia (reload) ustawień… A tak wpis sobie czeka już gotowy, aż na serwerze pojawi się odpowiedni plik.

Pracujemy nad nową wersją strony, a inni widzą starą wersję

Załóżmy, że mamy jakąś stronę, ale chcemy w sposób przezroczysty dla użytkowników przygotować nową odsłonę.

Dla jednego z klientów przygotowuje kilka stron internetowych – część jest nowa, więc wystarczy blokada lub przekierowanie na „zaślepkę” (podobnie jak w opisywanej powyżej sytuacji dotyczącej przerwy technicznej).

Tam gdzie strona już działa – sprawa komplikuje się trochę bardziej, bo chcemy przez te „kilka dni” jeszcze utrzymać starą stronę aktywną, gdy w tym czasie szykujemy nową.

Oczywiście można by tu skorzystać ze środowiska testowego, czy subdomeny – ale uznajmy, że środowisko testowe to jednak środowisko testowe, i często po migracji do środowiska produkcyjnego coś będzie nie tak… A subdomena – niby może być w tym samym środowisku, ale po co komplikować sobie później życie… ;-)

Stara strona trafiła do katalogu „old” (oczywiście „old” to tylko nazwa katalogu na potrzeby tego wpisu), a w katalogu głównym powstaje w tym czasie nowa…

Całość – w sposób (pół)przezroczysty dla użytkowników – załatwia taki wpis:

location / {
if ($remote_addr !~ "^123.123.123.123"){
rewrite ^(.*)$ /old$1 redirect;
}
[ STANDARDOWY KOD, np.:
try_files $uri $uri/ /old/index.php?$args; ]
}

Jak w sytuacji powyżej – tak i tym razem zamiast „123.123.123.123” należy wstawić swój adres (lub adresy) IP, dzięki czemu sami nie będziemy przekierowywani…

W przypadku gdy strona wpadnie w zapętlenie, dodajemy jeszcze kod:

location /old {
[STANDARDOWY KOD]
}

Katalog „z plikami strony” zależnie od IP odwiedzającego

A teraz wersja preferowana przeze mnie, a zarazem naprawdę przezroczysta dla użytkownika i dla wyszukiwarek (SEO ;-)), bo nic się nie zmienia w linkach:

set $WWWDIR "stara_strona";
if ($remote_addr ~ NASZE_IP) {
set $WWWDIR "nowa_strona";
}
root /var/www/[DOMENA]/$WWWDIR/;

Gdy my odwiedzamy stronę (NASZE_IP) to serwer serwuje nam pliki z katalogu „nowa_strona”. Gdy stronę odwiedza „osoba postronna” serwer serwuje „starą stronę”, czyli pliki idą z katalogu „stara_strona”.

Katalog „z plikami strony” zależnie od IP odwiedzającego i przeglądarki

Sytuacja trochę się komplikuje, gdy potrzebujemy skorzystać z różnych warunków łącznie, np. gdy łączymy się ze wskazanego IP i korzystamy z wybranej przeglądarki – przydatne, gdy np. chcemy pracować nad nową wersja strony, a zarazem zachować dostęp do starej.

Niestety Nginx chyba nie obsługuje reguł łącznych (i), więc musimy zastosować tutaj mały trik:

set $WWWDIR "stara_strona";

if ($remote_addr ~ NASZE_IP) {
    set $test okA;
}

if ($http_user_agent ~ Firefox) {
    set $test "${TEST}okB";
}
        
if ($test = okAokB) { 
    set $WWWDIR "public_html";
} 

root /var/www/[DOMENA]/$WWWDIR/;

Korzystamy z dodatkowej zmiennej $TEST, która przy pierwszym warunku (poprawny adres IP) otrzymuje wartość „okA”, a następnie przy spełnionym drugim warunku (przeglądarka Firefox) otrzymuje dodatkowe znaki „okB” na końcu, co w rezultacie daje „okAokB”. I tylko gdy zmienna $TEST ma wartość „okAokB” – czyli spełnione oba warunki na raz – zostanie ustawiony odpowiedni (roboczy) katalog (public_html).

Katalog „z plikami strony” zależnie od ciasteczka

O ile w biurze mam stały adres IP, to zdarza się, że nad stroną „muszę” popracować też w drodze, gdzie z IP może być różnie. I choć w takich sytuacjach pomaga mi połączenie po VPNie, to jednak nie zawsze jest to możliwe. Do tego, czasem chcę pokazać projekt strony innej osobie, albo grupie osób, i… robi się żonglowanie adresami IP. pomijając już nawet to, że muszę wtedy klientowi tłumaczyć co to jest IP, i jak ma go uzyskać…

W takim przypadku stosuje jeszcze jeden warunek – sprawdzanie ciasteczka:

server { 
 [...]
 set $WWWDIR "stara_strona";
 if ($cookie_webinsiderpl = "test") {
 set $WWWDIR "public_html";
 } 
 root /var/www/[DOMENA]/$WWWDIR/;
 [...]
} 

Jeśli w przeglądarce będzie zapisane ciasteczko „webinsiderpl” o zawartości „test”, to  zostaną zaserwowane pliki nowej strony.

Oczywiście potrzebny jest jakiś mechanizm zapisujący odpowiednie ciasteczko w przeglądarce. Tu wystarczy odrobina PHP:

<?php
 $cookie_name = "webinsiderpl";
 $cookie_value = "test";
 setcookie( $cookie_name, $cookie_value, time() + 300, '/' ); // 300 = 300 sekund = 5 minut
 echo "Ciasteczko wygenerowane";
?>

Całość zapisuje na serwerze (np. w pliku cookie.php) w katalogu ze starą (by wygenerować ciasteczko) i nową stroną (by odświeżyć ciasteczko zanim wygaśnie), i przekazuje prostą instrukcję:

  • Wchodzisz na adres [domena]/cookie.php
  • Następnie wchodzisz standardowo na stronę
  • I tyle – zamiast starej strony widzisz nową

W powyższym przykładzie ciasteczko jest ważne przez 5 minut (300 sekund), po tym czasie – jeśli nie zostanie wygenerowane ponownie – zamiast nowej strony ponownie będzie się wyświetlać stara strona.

A gdy nowa strona będzie już gotowa – wystarczy usunąć te kilka linijek.

Nginx, $remote_addr i Cloudflare

W przypadku gdy korzystacie z Cloudflare jest spora szansa, że przekierowanie nie będzie działać prawidło dla Waszego IP, tzn. nie rozpozna Was (Waszego IP).

W takim przypadku w pliku z konfiguracją danego vHosta, tuż nad regułką sprawdzającą czy IP należy do Was należy dodać:

# Cloudflare IP
 set_real_ip_from 199.27.128.0/21;
 set_real_ip_from 173.245.48.0/20;
 set_real_ip_from 103.21.244.0/22;
 set_real_ip_from 103.22.200.0/22;
 set_real_ip_from 103.31.4.0/22;
 set_real_ip_from 141.101.64.0/18;
 set_real_ip_from 108.162.192.0/18;
 set_real_ip_from 190.93.240.0/20;
 set_real_ip_from 188.114.96.0/20;
 set_real_ip_from 197.234.240.0/22;
 set_real_ip_from 198.41.128.0/17;
 set_real_ip_from 162.158.0.0/15;
 set_real_ip_from 104.16.0.0/12;
 set_real_ip_from 2400:cb00::/32;
 set_real_ip_from 2606:4700::/32;
 set_real_ip_from 2803:f800::/32;
 set_real_ip_from 2405:b500::/32;
 set_real_ip_from 2405:8100::/32;
 real_ip_header CF-Connecting-IP;
 real_ip_recursive on;
 # /Cloudflare IP

Jest to lista aktualna „na dziś”, więc może się z czasem zmieniać – na tej stronie znajdziecie aktualną listę adresów wykorzystywanych przez Cloudflare, możecie też skorzystać ze skryptu automatycznie pobierające aktualne adresy IP należące do serwerów Cloudflare.

(!) Zgłoś błąd na stronie
Pomogłem? To może postawisz mi wirtualną kawę?
LUTy dla D-Cinelike (DJI Mini 3 Pro, DJI Avata, OSMO Pocket) od MiniFly
Wdrożenie Omnibusa w sklepie na WooCommerce
Jak (legalnie) latać dronem w Kategorii Otwartej
Patryk