.. _apache-vhosts: Apache - virtuelle Hosts ######################## - Datum: 2024-06-13 - Distribution: getestet mit Debian 12 (ebenso mit Debian 11 und 10 machbar) Mit virtuellen Hosts lassen sich mehrere Kunden mittels nur einer Apache-Installation bedienen. Man unterscheidet: 1. IP-basierte virtuelle Hosts (die Netzwerkkarte erhält mehrere Adressen, früher: IPv4-Aliase) 2. Namensbasierte virtuelle Hosts (der Host hat nur eine Adresse, wird aber über mehrere Namen angesprochen) Die Webdokumente werden dann aus verschiedenen Verzeichnissen ausgeliefert, in unserem Fall seien dies :: /srv/vhosts/firma1 /srv/vhosts/firma2 Um die Konfigurationsdateien anschaulich ohne Kommentare und Leerzeilen ausgeben zu können, ist der folgende Alias sinnvoll: :: alias gg="grep --color -Ev '^\s*#|^$'" alias gg >> ~/.bashrc IP-basierte virtuelle Hosts =========================== Das Folgende soll nur als Übersicht dienen. Im einfachsten Fall werden einer Netzwerkkarte mittels Aliasen mehrere Adressen mitgegeben: :: ifconfig eth0:0 80.0.0.1 netmask 255.255.255.224 # für Firma 1 ifconfig eth0:1 80.0.0.2 netmask 255.255.255.224 # für Firma 2 Die erste Konfigurationsdatei würde dann entsprechend so aussehen, man beachte ````, außerdem muss als wichtige Direktive ``ServerName`` aktiviert und angepasst werden: :: ServerName www.firma1.test ServerAlias debvhost.firma1.test ServerAdmin webmaster@firma1.test DocumentRoot /srv/vhosts/firma1 Options none AllowOverride none Require all granted ErrorLog ${APACHE_LOG_DIR}/error-firma1.log CustomLog ${APACHE_LOG_DIR}/access-firma1.log combined Die zweite Konfigurationsdatei sieht dann in etwa so aus, man beachte wiederum die erste Zeile, nunmehr auf ```` geändert, weiterhin spielt die Zeile ``ServerName www.firma2.test`` eine wichtige Rolle: :: ServerName www.firma2.test ServerAlias debvhost.firma2.test ServerAdmin webmaster@firma2.test DocumentRoot /srv/vhosts/firma2 Options none AllowOverride none Require all granted ErrorLog ${APACHE_LOG_DIR}/error-firma2.log CustomLog ${APACHE_LOG_DIR}/access-firma2.log combined Schließlich muss die Namensauflösung z.B. mittels ``/etc/hosts`` mit zwei IP-Adressen durchgeführt werden: :: 80.0.0.1 www.firma1.test debvhost.firma1.test 80.0.0.2 www.firma2.test debvhost.firma2.test Namensbasierte virtuelle Hosts ============================== In älteren Apache-Versionen gab es dazu als Voraussetzung in der globalen ``httpd.conf`` die Anweisung ``NameVirtualHost *:80``, die aber nur das Akzeptieren von bestimmten Requests betraf und nicht das Port-Listening definiert (das geschieht mittels ``Listen 80``). Siehe dazu https://httpd.apache.org/docs/2.2/en/vhosts/name-based.html Die grundlegenden Schritte zur praktischen Einrichtung sind: 1. Verschiedene Verzeichnisse für DocumentRoot erzeugen, z.B. /srv/vhosts/firma1 2. Dort drin unterschiedliche index.html Dateien erzeugen 3. Kopieren und Umbenennen der Datei 000-default.conf, z.B. in firma1.conf 4. Anpassungen in firma1.conf 5. Kopieren und Umbenennen der firma1.conf in firma2.conf 6. Aktivieren der VHosts, reload der Config 7. Namenausflösung sicherstellen (anfänglich/testweise in der /etc/hosts) 8. Testen... zu 1) und 2) DocumentRoot, Rechte und Webdokumente -------------------------------------------------- Zuerst legen wir die beiden Verzeichnisse an, setzen die Rechte so, dass Kunden selber Dateien ablegen können und erzeugen zwei Textdateien für das abschließende Testen. :: mkdir -p /srv/vhosts/firma{1,2} chown -v www-data: /srv/vhosts/firma? echo 'Das ist der erste VHost für Firma 1' > /srv/vhosts/firma1/index.html echo 'This is the VHost for Firma 2' > /srv/vhosts/firma2/index.html zu 3) und 4) Konfigurationsdatei für Firma1 erstellen ----------------------------------------------------- :: cd /etc/apache2/sites-available cp 000-default.conf firma1.conf vi firma1.conf gg firma1.conf ServerName www.firma1.test ServerAlias debvhost.firma1.test ServerAdmin webmaster@firma1.test DocumentRoot /srv/vhosts/firma1 Options none AllowOverride none Require all granted ErrorLog ${APACHE_LOG_DIR}/error-firma1.log CustomLog ${APACHE_LOG_DIR}/access-firma1.log combined zu 5) Konfigurationsdatei für Firma2 erstellen ---------------------------------------------- :: gg firma1.conf | sed 's/firma1/firma2/g' > firma2.conf cat firma2.conf ServerName www.firma2.test ServerAlias debvhost.firma2.test ServerAdmin webmaster@firma2.test DocumentRoot /srv/vhosts/firma2 Options none AllowOverride none Require all granted ErrorLog ${APACHE_LOG_DIR}/error-firma2.log CustomLog ${APACHE_LOG_DIR}/access-firma2.log combined zu 6) Aktivieren der VHosts, reload der Config ---------------------------------------------- :: a2ensite firma1 a2ensite firma2 ls -ltrc /etc/apache2/sites-enabled/ apachectl graceful zu 7) Namenausflösung sicherstellen (anfänglich/testweise in der /etc/hosts) ---------------------------------------------------------------------------- :: echo '127.0.0.1 debvhost.firma1.test debvhost.firma2.test' >> /etc/hosts echo '127.0.0.1 www.firma1.test www.firma2.test firma1.test firma2.test' >> /etc/hosts zu 8) Testen der Vhost-Konfiguration ------------------------------------ :: # Es erscheint "Das ist der erste VHost für Firma 1": wget -qO- debvhost.firma1.test wget -qO- www.firma1.test # Es erscheint "This is the VHost for Firma 2": wget -qO- debvhost.firma2.test wget -qO- www.firma2.test .. _privates-verzeichnis: Privates Verzeichnis für Firma 2 ================================ Für Firma 2 soll nun ein privates Verzeichnis mit Zugriffsschutz eingerichtet werden, hier direkt in der Konfigurationsdatei (also nicht mittels separater ``.htaccess``-Datei, das ist unter :ref:`via-htaccess` beschrieben). Zuerst legen wir das Verzeichnis und ein kleines Webdokument an: :: mkdir /srv/vhosts/firma2/private echo "Willkommen im privaten Verzeichnis." > /srv/vhosts/firma2/private/index.html Nun folgt das Ergänzen der Konfigurationsdatei ``/etc/apache2/sites-enabled/firma2.conf`` um 6 Zeilen, beginnend mit der einleitenden Zeile, die das neue Verzeichnis definiert: ````. Ohne Kommentare sieht diese Konfigurationsdatei schließlich so aus: :: ServerName www.firma2.test ServerAlias debvhost.firma2.test ServerAdmin webmaster@firma2.test DocumentRoot /srv/vhosts/firma2 Options none AllowOverride none Require all granted AuthName "Private" AuthType Basic AuthUserFile /etc/apache2/passwords/access-passwd.firma2 Require valid-user ErrorLog ${APACHE_LOG_DIR}/error-firma2.log CustomLog ${APACHE_LOG_DIR}/access-firma2.log combined Nicht vergessen, diese Änderung mit ``apachectl graceful`` einzulesen! Jetzt wird noch eine entsprechende Password-Datei mit zwei Benutzern erzeugt (bei der zweiten Zeile ``-c`` weglassen!!): :: htpasswd -c /etc/apache2/passwords/access-passwd.firma2 user01 htpasswd /etc/apache2/passwords/access-passwd.firma2 user02 Und schließlich kann es schon ans Testen gehen; ohne die Benutzerauthentifizierung erhalten wir aber keinen Output (wget-Fehler via Exit-Code 6): :: wget -qO- www.firma2.test/private/ ; echo $? Übergeben wir nun aber den Benutzernamen samt Passwort, wird "Willkommen im privaten Verzeichnis." mit dem nachfolgenden Exit-Code 0 (Erfolg) ausgegeben: :: wget -qO- --user="user01" --password="1234567" www.firma2.test/private/ ; echo $? DNS-Zonen für die virtuellen Hosts in Apache ============================================ Anstelle der einfachen, dezentralen Namensauflösung mittels '/etc/hosts', ist für jeden Kunden eine eigene Zone empfehlenswert. Dazu hier zwei Beispiele für unsere VHosts mittels ``bind9``. Diese Zonendefinitionen werden einfach zur bestehenden Datei '/etc/bind/named.conf.local' hinzugefügt. :: zone "firma1.test" { type master; file "/var/lib/bind/db.firma1.test"; }; zone "firma2.test" { type master; file "/var/lib/bind/db.firma2.test"; }; Und dazu ein erstes passendes Zonenfile als Beispiel (db.firma1.test): :: $TTL 604800 @ IN SOA dns1.firma1.test. root.dns1.firma1.test. ( 5 ; Serial 604800 ; Refresh 86400 ; Retry 2419200 ; Expire 604800 ) ; Negative Cache TTL ; @ IN NS dns1.firma1.test. ; A-Records sind auf alle Fäller erforderlich, ein CNAME-Record wird ; mittels dem tatsächlichen Hostnamen realisiert: dns1 IN A 10.0.2.200 dns1 IN A 192.168.2.222 ; Für ganz kurzen Aufruf: nslookup firma1.test @ IN A 10.0.2.200 @ IN A 192.168.2.222 www IN CNAME dns1 Im zweiten Zonenfile (db.firma2.test) ist der Hostname **dns1** wiederum derselbe, nur der Domänennname ändert sich: :: $TTL 604800 @ IN SOA dns1.firma2.test. root.dns1.firma2.test. ( 5 ; Serial 604800 ; Refresh 86400 ; Retry 2419200 ; Expire 604800 ) ; Negative Cache TTL ; @ IN NS dns1.firma2.test. ; A-Records sind auf alle Fäller erforderlich, ein CNAME-Record wird ; mittels dem tatsächlichen Hostnamen realisiert: dns1 IN A 10.0.2.200 dns1 IN A 192.168.2.222 ; Für ganz kurzen Aufruf: nslookup firma2.test @ IN A 10.0.2.200 @ IN A 192.168.2.222 www IN CNAME dns1 SSL-Verschlüsselung für die virtuellen Hosts ============================================ Skizzierung der wichtigsten Schritte für Apache 2.2.22 :: $ cd /etc/ssl/ $ openssl req -new -outform PEM -out certs/testing.pem -newkey rsa:2048 -nodes \ -keyout private/testing.key -keyform PEM -days 3650 -x509 $ openssl x509 -fingerprint -noout -in certs/testing.pem :: $ a2enmod ssl Konfiguration für VHost 1 ------------------------- :: $ cd /etc/apache2/sites-available/ $ cp default-ssl test01.test-ssl :: $ vi test01.test-ssl :: Anpassen: Anpassen: DocumentRoot, Directory- und Logfile-Einstellungen (s.o.) Anpassen: Namen der Zertifikatsdateien (.pem und .key der Direktiven SSLCertificateFile bzw. SSLCertificateKeyFile) :: $ a2ensite test01.test-ssl Konfiguration für VHost 2 ------------------------- :: $ cp test01.test-ssl test02.test-ssl :: $ vi test02.test_ssl :: Anpassen: Anpassen: DocumentRoot, Directory- und Logfile-Einstellungen (s.o.) Anpassen: Namen der Zertifikatsdateien (.pem und .key der Direktiven SSLCertificateFile bzw. SSLCertificateKeyFile) :: $ a2ensite test02.test-ssl :: $ /etc/init.d/apache2 restart Tests im Browser ---------------- :: https://192.168.0.222/ <--- kein Zugang (Versuch, die Website zu identifizieren ist fehlgeschlagen)! https://www.test01.test/ <-- OK https://www.test02.test/ <-- OK Aktivieren von SSL für mehrere virtuelle Hosts (Server Name Indication) ----------------------------------------------------------------------- A) Änderung in der Datei */etc/apache2/ports.conf* Im Abschnitt ** oberhalb der Zeile *Listen 443* hinzufügen von (bei Apache 2.4 gibt es "NameVirtualHost" nicht mehr): :: NameVirtualHost *:443 B) Anpassung der betreffenden Vhost-Konfiguration für SSL Änderung von ** auf :: **Erzwingen von https beim Zugriff auf ein Unterverzeichnis** Voraussetzung: ``a2enmod rewrite`` In der Vhost-Konfiguration FÜR PORT 80 unterhalb von ``DocumentRoot /var/www/test02.test`` hinzuzufügen: :: # Nur für das Unterverzeichnis 'mail' die Verschlüsselung erzwingen RewriteEngine on ReWriteCond %{SERVER_PORT} !^443$ RewriteRule ^/mail/(.*) https://%{HTTP_HOST}/mail/$1 [NC,R,L] Zur Bedeutung der Flags: nocase\|NC Beim Suchmuster wird nicht zwischen Groß- und Kleinschreibung unterschieden redirect\|R[=Statuscode] Normalerweise sorgt RewriteRule für eine interne URI-Änderung last\|L Mit diesem Flag können Sie dafür sorgen, dass das Rewriting sofort beendet wird; weitere RewriteRules werden nicht mehr beachtet. Siehe auch: - http://httpd.apache.org/docs/2.2/rewrite/flags.html - http://www.workingwith.me.uk/articles/scripting/mod_rewrite - http://buecher.lingoworld.de/apache2/showdir.php?id=676