Przy okazji omawiania tematu Linuxa oraz serwerów, na tym blogu zostało poruszonych wiele tematów. Większość z nich dotyczy stricte aplikacji webowych, używania Pingwina w podstawowy sposób i tego, jak zorganizowane są pliki z oprogramowaniem na serwerze. Trochę mniej wspominaliśmy o tym, że jeśli już strona znajdzie się na komputerze umieszczonym w sieci, to dobrze by było, gdyby użytkownicy mogli ją znaleźć. I nie mamy na myśli pozycjonowania w Google (SEO, co jest zupełnie innym tematem, bardzo szerokim) - bardziej chodzi o to, aby mając adres strony można było po prostu ją otworzyć. Wbrew pozorom nie jest to takie oczywiste, szczególnie na maszynach, które pozwalają hostować wiele stron.
Niektórzy naturalnie tutaj pomyślą o domenach i protokole DNS i o ile siłą rzeczy zahaczymy o ten temat, to nie jest on istotą tego tekstu. Bardziej chcielibyśmy się skupić na tym, czym zakończyliśmy poprzedni akapit - na serwerze może znaleźć się wiele stron, także niezwiązanych ze sobą, a użytkownik chciałby dostać się do konkretnej z nich. Jak to zrobić?
Do tego służy mechanizm, który zwyczajowo nazywa się wirtualnymi hostami lub vhostami i ten właśnie sobie dzisiaj omówimy. Pośrednio zrobiliśmy to przy okazji artykułu o posługiwaniu się serwerem dla początkujących, ale dzisiaj rozszerzymy temat i pokażemy przykłady. Zademonstrujemy również, jak dostać się do strony, nie mając domeny lub chcąc, aby wskazywała na coś innego niż faktycznie wskazuje.
Czym jest host?
Na początku odpowiedzmy sobie na pytanie, czym w ogóle jest host, jeszcze bez przymiotnika "wirtualny". Osoby bardziej biegłe w angielskim od razu stwierdzą, że to "gospodarz" i dobrze oddaje to też znaczenie tego terminu w informatyce. Jest to maszyna lub serwer, który gromadzi u siebie ("hostuje") pewne zasoby, które następnie może udostępniać przez sieć, zarówno globalną, jak i lokalną. Może to być cokolwiek i niekoniecznie chodzi tutaj o stronę internetową - dotyczy to także zwykłej wymiany plików czy jakiejś usługi, jak np. SSH.
Jednak w naszym kontekście najczęściej jako hosta będziemy przyjmować komputer, który udostępnia pliki aplikacji webowej i to niekoniecznie jednej. Ważne jest to, że mówimy o urządzeniu, które faktycznie istnieje. Uwaga - niekoniecznie "fizycznie". Jest bowiem możliwość (i to bardzo często wykorzystywana), że jeden komputer tworzy maszyny wirtualne, które same w sobie są hostami. Jednak "gospodarza", będącego maszyną wirtualną, nie należy mylić z "wirtualnym hostem". To bowiem zupełnie inny byt.
Czym jest wirtualny host i jak obsługuje go serwer HTTP?
Wyobraźmy sobie sytuację, że mamy serwer pod adresem IP 10.20.30.40
, który zawiera aplikację z systemem klasy ERP (zarządzanie zasobami przedsiębiorstwa, jak np. ComMan). Jest to jedyny system na tej maszynie i prowadzi do niego adres MyERP.com
. Gdy użytkownik wpisze w przeglądarkę ten adres, serwer nazw domenowych poinformuje komputer, że host, którego szuka, znajduje się pod adresem 10.20.30.40
. Wówczas przeglądarka uda się pod wskazany adres, wchodząc na nasz serwer, a tam serwer HTTP zwróci zawartość plików strony.
Ten scenariusz jest prosty, ale bardzo... nierealistyczny. Po pierwsze, obecnie rzadko która aplikacja składa się z jednego komponentu posiadającego jeden adres. To akurat może, ale nie musi mieć znaczenia, gdyż dzieląc system na frontend i backend ten drugi zwykle jest ukryty przed dostępem z zewnątrz. Natomiast nie zawsze i to oznacza, że na jednym serwerze znajdują się dwie aplikacje pod różnymi adresami. To jednocześnie drugi powód - większość serwerów jest przeznaczona do hostowania wielu aplikacji webowych znajdujących się pod różnymi adresami za pomocą jednej maszyny i jednego serwera HTTP (czyli aplikacji, która serwuje strony, którymi zarządza). Z jednej strony dlatego, że tak jest taniej, a z drugiej niekiedy serwer jest "za duży", aby obsłużyć jedną aplikację i zwyczajnie można go zająć czymś jeszcze, aby nie marnować zasobów.
Zobaczmy taką perspektywę:

Użytkownik, chcąc wejść na stronę MyERP.com
, musi najpierw poznać adres IP serwera, który tę stronę przechowuje. Może to zrobić poprzez jeden z dostępnych serwerów DNS (ang. Domain Name Server), który ma coś w rodzaju tabelek mapujących adresy domenowe na adresy IP. W ten sposób przeglądarka użytkownika dowiaduje się, że interesujący go serwer ma "numer" 10.20.30.40
. Z tą wiedzą przeglądarka udaje się do tej maszyny i na tym rola DNS się kończy. Jego zadaniem było wskazanie odpowiedniego komputera i to tylko za pierwszym razem (lub raz na jakiś czas) - później przeglądarka cache'uje sobie ten adres, przyspieszając późniejszą drogę.
Przychodzi zatem żądanie do 10.20.30.40
, które przedstawia się jako żądanie do MyERP.com
- to szalenie istotna informacja. Służy bowiem serwerowi do tego, żeby rozpoznać, do którego ze zdefiniowanych dla siebie wirtualnych hostów (ang. virtual hosts, w skrócie vhosts) przekierować żądanie niczym router. Każdy z nich ma bowiem swoje dane konfiguracyjne i wskazany folder, w którym przechowuje pliki, składające się na aplikację. Jest to zatem taki lokator w wielkim bloku mieszkalnym zwanym serwerem HTTP. Tutaj warto też zauważyć, że sprawy nie rozwiązuje wpisanie w pasku adresu bezpośrednio 10.20.30.40
- serwer znajdziemy, ale ten nie będzie mógł zdecydować, o którą witrynę nam chodzi i w efekcie użytkownik uzyska błąd.
Ponieważ czasem lepiej pokazać coś za pomocą metafory, to spróbujmy. Wyobraźmy sobie młodzieńca Krzysia (użytkownik i jego przeglądarka), który chce zaprosić na bal Zosię (strona internetowa). Od kolegów (serwer DNS) dowiaduje się, że dom Zosi (adres domenowy) znajduje się na Lipowej 46 (adres IP). Zatem nasz Krzyś idzie na tę Lipową, puka do drzwi i po chwili widzi postawnego pana o groźnej minie (serwer HTTP), przedstawiającego się jako gospodarz. Niezrażony tym młodzieniec mówi, że przyszedł do córki rzeczonego gospodarza. Na to ten dopytuje "do której?" - ma bowiem aż trzy: Kasię, Zosię oraz Martę (wirtualne hosty). Krzyś wskazuje, że chodzi o Zosię, więc ojciec woła ją i ta wychodzi do chłopaka, wysłuchując zaproszenia na bal.
Jak widać, pojęcie wirtualnego hosta jest dość proste - to coś w rodzaju jednego z nazwanych zasobów dostępnych przez adres URL, które są na serwerze. Natomiast trochę trudniejsze zadanie czeka tych, którzy muszą takie wirtualne hosty zdefiniować, gdyż nie zawsze jest to proste, zwłaszcza, że wykonuje się to inaczej na każdym rodzaju serwera HTTP.
Konfiguracja Apache
Jest to drugi najpopularniejszy aplikacyjny serwer HTTP używany na serwerach, ale najbardziej rozchwytywany przez początkujących (choć nie tylko i od razu to napiszę wyraźnie - to żadna ujma). Wynika to z jego prostoty konfiguracji (przynajmniej na tle konkurentów), natomiast trzeba zdawać sobie sprawę, że jest uznawany za wolniejszy względem np. NGINX. Tym niemniej, wszystko zależy od wymagań pozafunkcjonalnych systemu, który ma być hostowany za pomocą takiego serwera. Sam serwer często jest nazywany Apache 2, gdyż druga wersja jest od wielu lat wiodąca. Raz zdarzyło mi się po poprosić administratora o serwer Apache'a i dostałem Apache'a w wersji pierwszej, mimo że od wielu lat była dostępna "dwójka".
W tym przypadku wirtualne hosty definiuje się w folderze /etc/apache2/sites-available
(używamy domyślnych ścieżek linuxowych), zazwyczaj tworząc osobne pliki tekstowe dla każdego vhosta. Ułatwia to ich późniejsze włączanie i wyłączanie.
Poniżej znajduje się przykład pliku myerp.com.conf
, który definiuje vhost myerp.com
:
<VirtualHost *:80> DocumentRoot /var/www/myerp.com ServerName myerp.com ServerAlias www.myerp.com ServerAdmin admin@myerp.com ErrorLog ${APACHE_LOG_DIR}/myerp.com-error.log CustomLog ${APACHE_LOG_DIR}/myerp.com-access.log common <Directory /var/www/myerp.com> Allow from all Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory> </VirtualHost>
Każdą definicję zawieramy w węźle VirtualHost
podając konkretny adres i port lub używając właśnie gwiazdki jako dowolnego adresu IP, który i tak zaprowadził użytkownika na nasz serwer. Najważniejsze są pierwsze dwie instrukcje - DocumentRoot
określa lokalizację plików aplikacji, natomiast ServerName
- adres, który wywołuje te pliki. Jak można się domyśleć z kodu, istnieje także możliwość określenia aliasu, administratora oraz lokalizacji plików z logami.
Ważną definicję stanowi też węzeł Directory
, który nie jest obowiązkowy, ale służy m.in. do ustawienia AllowOverride All
, pozwalający na nadpisywanie reguł poprzez pliki .htaccess
w samej aplikacji, tak charakterystyczne dla serwera Apache'a. Oprócz tego, jak widać, można m.in. odblokować dostęp z każdego miejsca.
Jednak umieszczenie konfiguracji w folderze sites-available
to tylko połowa sukcesu - konfigurację trzeba też włączyć (lub wyłączyć, jeśli jej już nie potrzebujemy). Do tego służą odpowiednie komendy:
sudo a2ensite myerp.com.conf sudo a2dissite myerp.com.conf
Zmiany konfiguracyjne należy zaaplikować poprzez restart samego serwera w sposób zależny od konkretnej dystrybucji Linuxa. Przykładowo:
sudo systemctl reload apache2
Więcej informacji znajdziecie w tym łatwo zrozumiałym poradniku od DigitalOcean.
Konfiguracja XAMPP
XAMPP to znane narzędzie szczególnie na Windowsie, które łączy w sobie serwer HTTP Apache'a, serwer MySQL-a (choć ten akurat osobiście polecam zainstalować osobno) i moduł interpretera PHP. Bardzo ułatwia tworzenie aplikacji i zdejmuje z programistów potrzebę samodzielnej konfiguracji wielu parametrów.
Jako że tak, jak napisałem, ten pakiet wykorzystuje pod spodem serwer Apache'a, tworzenie tutaj wirtualnych hostów wygląda bardzo podobnie jak to, co przedstawiliśmy wyżej. Różnica jest taka, że w tym przypadku domyślna lokalizacja pliku z wirtualnymi hostami (na Windowsie) to C:\xampp\apache\conf\extra\httpd-vhosts.conf
i jest to jeden plik obejmujący wszystkie takie wpisy. Bo tak - także w natywnym Apache'u (zresztą także w NGINX, który zaraz omówimy) można wszystkie vhosty zawrzeć w jednym pliku, tylko po prostu jest to mniej wygodne w późniejszym zarządzaniu na serwerze produkcyjnym.
Przy tej okazji warto wspomnieć o tym, że w tego typu lokalnych środowiskach nie należy zapominać o pozostawieniu dostępu do adresów localhost/nazwafolderu
, co jest bardzo pomocne podczas rozwijania wielu aplikacji na komputerze. Wówczas pomocna będzie następująca definicja vhosta:
<VirtualHost *:80> ServerAdmin localhost@example.com DocumentRoot "C:/xampp/htdocs" ServerName localhost.com ServerAlias www.localhost.com ErrorLog "logs/localhost-error.log" CustomLog "logs/localhost-access.log" common <Directory "C:/xampp/htdocs"> Allow from all Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory> </VirtualHost>
Konfiguracja MAMP
MAMP jest odpowiednikiem XAMPPa na systemach operacyjnych macOS. Swoją drogą, sam XAMPP też jest dostępny na Jabłkach, ale MAMP jest jeszcze prostszy i... czasem irytujący w darmowej wersji z uwagi na trochę utrudniony dostęp do pewnych plików konfiguracyjnych. Ale spokojnie - tutaj też można włączyć wirtualne hosty i to na podobnej zasadzie, jak w XAMPPie. Natomiast trzeba dodatkowo pamiętać o włączeniu samego mechanizmu w /Applications/MAMP/conf/apache/httpd.conf
, gdzie należy odkomentować linijkę:
Include /Applications/MAMP/conf/apache/extra/httpd-vhosts.conf
Jak się możecie domyślać, wskazuje ona lokalizację pliku z definicjami wirtualnych hostów, gdzie kwestia wygląda tak samo, jak opisano powyżej. Warto też wspomnieć, że MAMP umożliwia przełączenie się z Apache'a na NGINX. A właśnie.
Konfiguracja NGINX
Według badań z czerwca 2022 roku jest to najpopularniejszy serwer HTTP na świecie (33,6%, podczas gdy drugi Apache ma 31,4% udziału), jeśli mówimy o środowiskach produkcyjnych. To właśnie w nich NGINX pokazuje swoją szybkość i możliwości, w wyniku których jest szeroko wykorzystywany do serwerowania stron WWW, jako load balancer, serwer reverse proxy i w innych przypadkach. Dlaczego zatem sugerowałem, że Apache jest najpopularniejszym serwerem wśród początkujących? Ponieważ ma ciut prostszą strukturę i sposób definiowania konfiguracji. To nie jest też tak, że jeśli ktoś używa NGINX-a to jest automatycznie profesjonalistą, a "apaczowcy" są słabsi - oba serwery HTTP są dobre, tylko każdy z nich ma pewne zalety i wady, które nie zawsze muszą być kluczowe. Jeśli kluczowa jest wydajność, to nie da się ukryć, że NGINX jest preferowany.
Jeżeli chodzi o wirtualne hosty, to w przypadku NGINX-a mówimy o czymś, co się nazwa server blockami. Dobrą informacją jest to, że co do zasady definiuje się je bardzo podobnie jak w Apache - interesuje nas folder /etc/nginx/sites-available
, w którym tworzymy pliki dla każdej strony, a które wyglądają mniej więcej tak:
server { listen 80; listen [::]:80; root /var/www/myerp.com; index index.html index.htm index.nginx-debian.html; server_name myerp.com www.myerp.com; location / { try_files $uri $uri/ =404; } }
Jak widać, struktura wydaje się nieco bardziej kompaktowa, natomiast różnice pod spodem są większe i sposób definiowania np. ścieżek przekierowań w NGINX jest zupełnie inny. Natomiast, żeby włączyć vhosta, także tutaj należy podlinkować odpowiedni plik w katalogu sites-enabled
(tym razem standardową komendą linkowania):
sudo ln -s /etc/nginx/sites-available/myerp.com /etc/nginx/sites-enabled/
a następnie sprawdzić i zrestartować NGINX-a:
sudo nginx -t sudo systemctl restart nginx
Również w tym przypadku polecamy tutorial autorstwa DigitalOcean, który tłumaczy cały proces krok po kroku.
Konfiguracja Caddy
Wraz z upowszechnieniem się języka programowania Go, środowisko programistyczne zostało zasilone narzędziami, z których niektóre weszły do szerszego użytku. Jednym z nich jest Caddy, prosty serwer webowy, który jest podatny na rozszerzanie i - co ciekawe - automatycznie zapewnia protokół szyfrowany. Jest przedstawiany jako bezpieczniejszy i przede wszystkim prostszy w konfiguracji serwer, nawet od Apache.
Choć z tym prostszym bym może nie przesadzał - jak każde narzędzie wymaga zapoznania się i samodzielnych prób, w trakcie których niektóre osoby zrażą się do Caddy'ego, a inne nim zachwycą. Ten serwer jest używany między innymi przez /kbin i tworzenie wirtualnych hostów wygląda tutaj dość prosto:
myerp.com { root * /var/www/myerp file_server }
Więcej informacji możecie przeczytać w tym artykule oraz, oczywiście, oficjalnej dokumentacji. A samego Caddy'ego możecie poznać poprzez przykład podany na stronach - a jakże - DigitalOcean.
Czym jest /etc/hosts?
Wróćmy jeszcze na chwilę do wcześniej przytoczonego tłumaczenia tego, jak użytkownik dostaje się w ogóle do strony i skupmy się na tej pierwszej części - kontakcie z serwerem DNS. Zakładamy bowiem, że przykładowa domena MyERP.com
jest zarejestrowana i dostępna publicznie. Wówczas rzeczywiście powinniśmy podążać tą ścieżką. Jednak, jak zawsze, można znaleźć co najmniej trzy sytuacje wyjątkowe, kiedy trzeba podejść do tego inaczej.
Pierwsza z nich to taka, w której strona, do której chcemy się dostać, znajduje się już pod nowym adresem IP (np. została przeniesiona na inny serwer), ale serwer DNS jeszcze o tym nie wie. Nie ma w tym niczego dziwnego - tzw. propagacja zmian na serwerach DNS może trwać od kilkunastu minut do nawet 48 godzin, w związku z czym zmiana adresu domenowego tak, aby wskazywał na inny serwer może nie być u wszystkich widoczna od razu. Dodatkowo, może zaistnieć sytuacja, w której serwery DNS zwracają już poprawne rekordy, ale u nas nadal aktywny jest cache, a chwilowo nie możemy lub nie umiemy go wyczyścić.
Druga sytuacja jest podobna, ale dotyczy awarii serwerów DNS lub braku możliwości odwołania się do nich - bywają takie błędy. Do tej puli wpada też np. ominięcie jakichś blokad bądź zrobienie żartu koledze z pracy, ale tego ostatniego, oczywiście, nie polecamy.
Trzecia sytuacja jest również ciekawa, gdyż domena może nie istnieć publicznie. Można się umówić w firmie, że jakaś witryna będzie dostępna pod adresem myerp.local
i jest to URL używany tylko w obrębie tego środowiska. Nie chcemy lub nie możemy tej domeny zarejestrować publicznie, a więc umieścić ją na serwerach DNS. A jednak jakoś przeglądarka będzie musiała się dowiedzieć, gdzie kierować się po wpisaniu tego adresu.
Gdy adresujemy jeden z powyżej opisanych problemów do kogoś, kto może nam pomóc, często usłyszymy "dodaj wpisy do /etc/hosts". Jest to bowiem plik systemowy, który służy do lokalnego podania stałego adresu IP, który jest przypisany danemu adresowi domenowemu. Jest to zatem taka lokalna uproszczona wersja serwera DNS dostępna tylko dla nas i nadrzędna względem DNS-ów. Przykładowo, jeśli pod adres youtube.com
przypiszemy w tym pliku 91.185.189.246
, to po wpisaniu "youtube.com" w przeglądarce wylądujemy tak naprawdę w Feedybacky.
Budowa tego pliku jest prosta, aczkolwiek warto wspomnieć, że możemy go edytować tylko z uprawnieniami administratora. Oto przykładowy fragment /etc/hosts
:
120.50.66.171 system.test.com 127.0.0.1 local.site1 127.0.0.1 local.site2
Te reguły mówią nam o tym, że jeśli użytkownik na tym komputerze odwoła się do adresu system.test.com
, to trafi pod adres IP 120.50.66.171
. Ma też dwa wirtualne hosty skonfigurowane na swojej maszynie, czyli localhoście (zwyczajowa nazwa 127.0.0.1
) - są to local.site1
oraz local.site2
. Jak widać, potwierdza się, że można jednemu adresowi IP przypisać przypisać wiele domen lub pseudodomen.
Sam plik /etc/hosts
znajduje się właśnie w tej lokalizacji w Linuxach i systemach macOS. Ale także Windows posiada taki zbiór dyskowy, tylko w trochę trudniejszym do zapamiętania folderze - C:/Windows/System32/drivers/etc/hosts
.
Podsumowanie
Mamy nadzieję, że tym tekstem rozświetliliśmy choć trochę temat wirtualnych hostów - to nie jest nic strasznego, za to wręcz stanowi wymagany mechanizm przy projektowaniu nowoczesnego oprogramowania, a także przy zarządzaniu serwerem HTTP, na którym znajduje się wiele stron. W tym momencie niektórzy mogą zadać sobie pytanie, kto konfiguruje vhosty i odpowiedź brzmi: administratorzy przy wsparciu instrukcji od programistów. Tutaj nie ma też co się łudzić, że koderzy ustawią wszystko od A do Z - często wymagają pomocy administratorów, którzy jednak potrzebują dokładnych wytycznych dotyczących tego, co ma być osiągnięte.
Pozdrawiam i dziękuję - Jakub Rojek.