.. sectionauthor:: |vedranmiletic| Konfiguracija virtualnih domaćina u web poslužitelju Apache HTTP Server ======================================================================= Konfiguracijska naredba ```` (`dokumentacija `__) omogućuje Apacheju da poslužuje više različitih web sjedišta koja se nalaze na više različitih domena putem jedne IP adrese i vrata. Primjer primjene virtualnih domaćina ------------------------------------ Ilustracije radi, promotrimo web sjedišta ``www.math.uniri.hr``, ``www.phy.uniri.hr`` i ``www.biotech.uniri.hr``. :: $ curl -v -I http://www.phy.uniri.hr/hr/ * Trying 193.198.209.33:80... * Connected to www.phy.uniri.hr (193.198.209.33) port 80 (#0) > HEAD /hr/ HTTP/1.1 > Host: www.phy.uniri.hr > User-Agent: curl/7.70.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK (...) $ curl -v -I http://www.math.uniri.hr/hr/ * Trying 193.198.209.33:80... * Connected to www.math.uniri.hr (193.198.209.33) port 80 (#0) > HEAD /hr/ HTTP/1.1 > Host: www.math.uniri.hr > User-Agent: curl/7.70.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK (...) $ curl -v -I http://www.biotech.uniri.hr/hr/ * Trying 193.198.209.33:80... * Connected to www.biotech.uniri.hr (193.198.209.33) port 80 (#0) > HEAD /hr/ HTTP/1.1 > Host: www.biotech.uniri.hr > User-Agent: curl/7.70.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK (...) Uočimo da se ova tri web sjedišta nalaze na istoj IP adresi (193.198.209.33) i istim vratima (80), ali poslužitelj zna točno koji sadržaj mora isporučiti u odgovoru zahvaljujući vrijednosti polja ``Host:`` u svakom od HTTP zahtjeva. Vrijednost tog polja se može postaviti u cURL-u kod slanja HTTP zahtjeva: :: $ curl --header "Host: www.math.uniri.hr" http://www.biotech.uniri.hr/hr/ Odjel za matematiku - Vijesti (...) Server Name Indication ---------------------- Ovaj pristup neće raditi kad se koristi HTTPS: :: curl --header "Host: www.math.uniri.hr" https://www.biotech.uniri.hr/hr/ 400 Bad Request

Bad Request

Your browser sent a request that this server could not understand.


Apache/2.4.10 (Debian) Server at www.math.uniri.hr Port 443
Razlog je da više HTTPS poslužitelja na jednoj IP adresi zahtijeva `Server Name Indication `__ (kraće SNI, dokumentiran u `RFC-u 6066: Transport Layer Security (TLS) Extensions: Extension Definitions u odjeljku 3. Server Name Indication `__). Za tu svrhu cURL ima parametre ``--resolve`` i ``--connect-to``, od kojih prvi koristimo u nastavku. Konfiguracija virtualnih domaćina za HTTP ----------------------------------------- Recimo da imamo dvije domene, ``prometej.rm.miletic.net`` i ``epimetej.rm.miletic.net`` te da želimo na njih postaviti dva različita web sjedišta. Stvorimo sadržaj tih web sjedišta: :: $ mkdir -p www/{epimetej,prometej}/html $ echo '

Epimetej

' > www/epimetej/html/index.html $ echo '

Prometej

' > www/prometej/html/index.html Apache koji koristimo već dolazi s konfiguracijskom datotekom za virtualne domaćine koju možemo prilagoditi i uključiti. Dohvatimo tu datoteku: :: $ sudo docker run --rm httpd:2.4 cat /usr/local/apache2/conf/extra/httpd-vhosts.conf > my-httpd-vhosts.conf Uredimo tu datoteku; uočimo da su nam konfiguracijske naredbe ``ServerAdmin``, ``ServerName`` i ``DocumentRoot`` već poznate, samo se nalaze unutar bloka naredbi ````: .. code-block:: apacheconf # Virtual Hosts # # Required modules: mod_log_config # If you want to maintain multiple domains/hostnames on your # machine you can setup VirtualHost containers for them. Most configurations # use only name-based virtual hosts so the server doesn't need to worry about # IP addresses. This is indicated by the asterisks in the directives below. # # Please see the documentation at # # for further details before you try to setup virtual hosts. # (...) ServerAdmin webmaster@dummy-host.example.com DocumentRoot "/usr/local/apache2/docs/dummy-host.example.com" ServerName dummy-host.example.com ServerAlias www.dummy-host.example.com ErrorLog "logs/dummy-host.example.com-error_log" CustomLog "logs/dummy-host.example.com-access_log" common ServerAdmin webmaster@dummy-host2.example.com DocumentRoot "/usr/local/apache2/docs/dummy-host2.example.com" ServerName dummy-host2.example.com ErrorLog "logs/dummy-host2.example.com-error_log" CustomLog "logs/dummy-host2.example.com-access_log" common Maknemo li konfiguracijsku naredbu ``ServerAdmin``, za taj virtualni domaćin koristit će se ona vrijednost koju smo već ranije postavili u datoteci ``my-httpd.conf``, što nam odgovara. Naredbu ``ServerAlias`` ne trebamo jer imamo samo jednu domenu po virtualnom domaćinu. Također, logging nam ovdje nije bitan pa ćemo i te dvije naredbe maknuti, čime smo eliminirali i potrebu za modulom `mod_log_config `__ koja se navodi u zaglavlju konfiguracijske datoteke u komentarima. Naposlijetku, moramo dodati dozvolu pristupa (``Require all granted``) za svaki od direktorija koji se koristi kao ``DocumentRoot``. Konfiguracija (zasad samo za HTTP vrata 80) je oblika: .. code-block:: apacheconf DocumentRoot "/var/www/epimetej/html" Require all granted ServerName epimetej.rm.miletic.net DocumentRoot "/var/www/prometej/html" Require all granted ServerName prometej.rm.miletic.net Kad se koriste virtualni domaćini, tada prvi navedeni u konfiguracijskoj datoteci postaje zadani virtualni domaćin i koristi se kod odgovora na zahtjeve kod kojih vrijednost u polju ``Host:`` ne odgovara ni jednoj vrijednosti konfiguracijske naredbe ``ServerName``. Zato je dobra praksa eksplicitno prvo navesti zadani virtualni domaćin: .. code-block:: apacheconf DocumentRoot "/var/www/html" DocumentRoot "/var/www/epimetej/html" Require all granted ServerName epimetej.rm.miletic.net DocumentRoot "/var/www/prometej/html" Require all granted ServerName prometej.rm.miletic.net U datoteci ``my-httpd.conf`` odkomentirajmo liniju koja uključuje konfiguracijsku datoteku koju smo upravo uredili: .. code-block:: apacheconf (...) # Virtual hosts #Include conf/extra/httpd-vhosts.conf (...) Promijenimo ``Dockerfile`` da uključuje novu datoteku, dodajmo još jednu naredbu ``COPY``: .. code-block:: dockerfile :emphasize-lines: 7 FROM httpd:2.4 COPY ./my-httpd.conf /usr/local/apache2/conf/httpd.conf COPY ./www /var/www COPY server.crt /usr/local/apache2/conf COPY server.key /usr/local/apache2/conf COPY ./my-httpd-ssl.conf /usr/local/apache2/conf/extra/httpd-ssl.conf COPY ./my-httpd-vhosts.conf /usr/local/apache2/conf/extra/httpd-vhosts.conf Izgradimo sliku i pokrenimo Docker kontejner: :: sudo docker build -t "my-httpd:2.4-5" . Sending build context to Docker daemon 54.78kB Step 1/7 : FROM httpd:2.4 ---> b2c2ab6dcf2e Step 2/7 : COPY ./my-httpd.conf /usr/local/apache2/conf/httpd.conf ---> e475515ada38 Step 3/7 : COPY ./www /var/www ---> c764360e0255 Step 4/7 : COPY server.crt /usr/local/apache2/conf ---> fc1bfa23df69 Step 5/7 : COPY server.key /usr/local/apache2/conf ---> b1b86d1c6b3d Step 6/7 : COPY ./my-httpd-ssl.conf /usr/local/apache2/conf/extra/httpd-ssl.conf ---> 9c09539265cd Step 7/7 : COPY ./my-httpd-vhosts.conf /usr/local/apache2/conf/extra/httpd-vhosts.conf ---> 7839a9247066 Successfully built 7839a9247066 Successfully tagged my-httpd:2.4-5 $ sudo docker run my-httpd:2.4-5 [Sun May 10 22:09:41.234807 2020] [ssl:warn] [pid 1:tid 139624574960768] AH01906: www.example.com:443:0 server certificate is a CA certificate (BasicConstraints: CA == TRUE !?) [Sun May 10 22:09:41.235132 2020] [ssl:warn] [pid 1:tid 139624574960768] AH01909: www.example.com:443:0 server certificate does NOT include an ID which matches the server name [Sun May 10 22:09:41.238436 2020] [ssl:warn] [pid 1:tid 139624574960768] AH01906: www.example.com:443:0 server certificate is a CA certificate (BasicConstraints: CA == TRUE !?) [Sun May 10 22:09:41.238443 2020] [ssl:warn] [pid 1:tid 139624574960768] AH01909: www.example.com:443:0 server certificate does NOT include an ID which matches the server name [Sun May 10 22:09:41.239474 2020] [mpm_event:notice] [pid 1:tid 139624574960768] AH00489: Apache/2.4.43 (Unix) OpenSSL/1.1.1d configured -- resuming normal operations [Sun May 10 22:09:41.239504 2020] [core:notice] [pid 1:tid 139624574960768] AH00094: Command line: 'httpd -D FOREGROUND' Uvjerimo se da nam virtualni domaćini rade: :: $ curl --header "Host: prometej.rm.miletic.net" http://172.17.0.2/

Prometej

$ curl --header "Host: epimetej.rm.miletic.net" http://172.17.0.2/

Epimetej

Uvjerimo se da nam zadani virtualni domaćin hvata sve zahtjeve koji ne pašu na ova dva iznad: :: $ curl http://172.17.0.2/

Radi!

$ curl --header "Host: atlas.rm.miletic.net" http://172.17.0.2/

Radi!

Konfiguracija virtualnih domaćina za HTTPS ------------------------------------------ Želimo li virtualne domaćine korisiti u kombinaciji s HTTPS-om, dodat ćemo u ``my-httpd-vhosts.conf`` blokove za virtualne domaćine na HTTPS vratima 443: .. code-block:: apacheconf DocumentRoot "/var/www/html" SSLCertificateFile "/usr/local/apache2/conf/server.crt" SSLCertificateKeyFile "/usr/local/apache2/conf/server.key" DocumentRoot "/var/www/epimetej/html" Require all granted ServerName epimetej.rm.miletic.net SSLCertificateFile "/usr/local/apache2/conf/epimetej.crt" SSLCertificateKeyFile "/usr/local/apache2/conf/epimetej.key" DocumentRoot "/var/www/prometej/html" Require all granted ServerName prometej.rm.miletic.net SSLCertificateFile "/usr/local/apache2/conf/prometej.crt" SSLCertificateKeyFile "/usr/local/apache2/conf/prometej.key" Vidimo da opet imamo zadani blok i onda po jedan blok za svako web sjedište. Ovi blokovi imaju dodatne konfiguracijske naredbe ``SSLCertificateFile`` i ``SSLCertificateKeyFile``. Certifikate i privatne ključeve ćemo kao i ranije generirati OpenSSL-om i paziti da pod ``Common Name`` navedemo imena domena: :: $ openssl req -x509 -nodes -days 30 -newkey rsa:4096 -keyout epimetej.key -out epimetej.crt (...) Common Name (e.g. server FQDN or YOUR name) []:epimetej.rm.miletic.net (...) $ openssl req -x509 -nodes -days 30 -newkey rsa:4096 -keyout prometej.key -out prometej.crt (...) Common Name (e.g. server FQDN or YOUR name) []:prometej.rm.miletic.net (...) ``Dockerfile`` ćemo dodati 4 nove naredbe ``COPY`` i sada je oblika: .. code-block:: dockerfile :emphasize-lines: 8-11 FROM httpd:2.4 COPY ./my-httpd.conf /usr/local/apache2/conf/httpd.conf COPY ./www /var/www COPY server.crt /usr/local/apache2/conf COPY server.key /usr/local/apache2/conf COPY ./my-httpd-ssl.conf /usr/local/apache2/conf/extra/httpd-ssl.conf COPY ./my-httpd-vhosts.conf /usr/local/apache2/conf/extra/httpd-vhosts.conf COPY epimetej.crt /usr/local/apache2/conf COPY epimetej.key /usr/local/apache2/conf COPY prometej.crt /usr/local/apache2/conf COPY prometej.key /usr/local/apache2/conf Izgradit ćemo sliku i pokrenut Docker kontejner: :: $ sudo docker build -t "my-httpd:2.4-6" . Sending build context to Docker daemon 72.7kB Step 1/11 : FROM httpd:2.4 ---> b2c2ab6dcf2e Step 2/11 : COPY ./my-httpd.conf /usr/local/apache2/conf/httpd.conf ---> Using cache ---> e475515ada38 Step 3/11 : COPY ./www /var/www ---> Using cache ---> c764360e0255 Step 4/11 : COPY server.crt /usr/local/apache2/conf ---> Using cache ---> fc1bfa23df69 Step 5/11 : COPY server.key /usr/local/apache2/conf ---> Using cache ---> b1b86d1c6b3d Step 6/11 : COPY ./my-httpd-ssl.conf /usr/local/apache2/conf/extra/httpd-ssl.conf ---> Using cache ---> 9c09539265cd Step 7/11 : COPY ./my-httpd-vhosts.conf /usr/local/apache2/conf/extra/httpd-vhosts.conf ---> 34ae4d97114f Step 8/11 : COPY epimetej.crt /usr/local/apache2/conf ---> 96fd7f0e9a88 Step 9/11 : COPY epimetej.key /usr/local/apache2/conf ---> 5a63ce1a7686 Step 10/11 : COPY prometej.crt /usr/local/apache2/conf ---> eb5005e4dbfe Step 11/11 : COPY prometej.key /usr/local/apache2/conf ---> 3b4c03a5e682 Successfully built 3b4c03a5e682 $ sudo docker run my-httpd:2.4-6 [Sun May 10 22:49:09.438791 2020] [ssl:warn] [pid 1:tid 140677310489728] AH01906: www.example.com:443:0 server certificate is a CA certificate (BasicConstraints: CA == TRUE !?) [Sun May 10 22:49:09.439105 2020] [ssl:warn] [pid 1:tid 140677310489728] AH01909: www.example.com:443:0 server certificate does NOT include an ID which matches the server name [Sun May 10 22:49:09.439521 2020] [ssl:warn] [pid 1:tid 140677310489728] AH01906: prometej.rm.miletic.net:80:0 server certificate is a CA certificate (BasicConstraints: CA == TRUE !?) [Sun May 10 22:49:09.439933 2020] [ssl:warn] [pid 1:tid 140677310489728] AH01906: epimetej.rm.miletic.net:80:0 server certificate is a CA certificate (BasicConstraints: CA == TRUE !?) [Sun May 10 22:49:09.443353 2020] [ssl:warn] [pid 1:tid 140677310489728] AH01906: www.example.com:443:0 server certificate is a CA certificate (BasicConstraints: CA == TRUE !?) [Sun May 10 22:49:09.443360 2020] [ssl:warn] [pid 1:tid 140677310489728] AH01909: www.example.com:443:0 server certificate does NOT include an ID which matches the server name [Sun May 10 22:49:09.443707 2020] [ssl:warn] [pid 1:tid 140677310489728] AH01906: prometej.rm.miletic.net:80:0 server certificate is a CA certificate (BasicConstraints: CA == TRUE !?) [Sun May 10 22:49:09.444046 2020] [ssl:warn] [pid 1:tid 140677310489728] AH01906: epimetej.rm.miletic.net:80:0 server certificate is a CA certificate (BasicConstraints: CA == TRUE !?) [Sun May 10 22:49:09.445125 2020] [mpm_event:notice] [pid 1:tid 140677310489728] AH00489: Apache/2.4.43 (Unix) OpenSSL/1.1.1d configured -- resuming normal operations [Sun May 10 22:49:09.445153 2020] [core:notice] [pid 1:tid 140677310489728] AH00094: Command line: 'httpd -D FOREGROUND' Sad možemo cURL-om isprobati da virtualni domaćini rade ispravno kad se koristi HTTPS (zbog SNI-ja nije dovoljno koristiti ``--header Host: ...`` pa koristimo ``--resolve``): :: $ curl -k --resolve prometej.rm.miletic.net:443:172.17.0.2 https://prometej.rm.miletic.net/

Prometej

$ curl -k --resolve epimetej.rm.miletic.net:443:172.17.0.2 https://epimetej.rm.miletic.net/

Epimetej

Mi ovdje cURL-u parametrom ``--resolve`` kažemo da preskoči DNS pretragu i zatraži URL-ove ``https://prometej.rm.miletic.net/`` i ``https://epimetej.rm.miletic.net/`` na adresi 172.17.0.2 i vratima 443. Uvjerimo se da ostali zahtjevi završavaju na zadanom virtualnom domaćinu: :: $ curl -k --resolve atlas.rm.miletic.net:443:172.17.0.2 https://atlas.rm.miletic.net/

Radi!

$ curl -k https://172.17.0.2/

Radi!