Apache
Virtual Hosts mit SSL
Echte IP-based Virtual Hosts
Die beliebten named-based Virtual Hosts lassen sich eigentlich mit SSL nicht verwenden (Begründung siehe hier). Man muss also pro Virtual Host eine separate IP-Adresse verwenden, z.B. durch Zuweisung einer Alias-IP-Adresse und (bei NAT) Umleitung eines zusätzlichen Ports vom Router.
Die Konfig sieht dann so aus:
<IfDefine SSL>
<IfDefine !NOSSL>
<Directory "/srv/www/vhosts/server1">
Options None
AllowOverride AuthConfig
Order allow,deny
Allow from all
</Directory>
<Directory "/srv/www/vhosts/server2">
Options None
AllowOverride AuthConfig
Order allow,deny
Allow from all
</Directory>
<VirtualHost 1.1.1.1:443>
...
DocumentRoot "/srv/www/vhosts/server1"
...
SSLCertificateFile /etc/apache2/ssl.crt/server1.crt
SSLCertificateKeyFile /etc/apache2/ssl.key/server1.key
...
</VirtualHost>
<VirtualHost 1.1.1.2:443>
...
DocumentRoot "/srv/www/vhosts/server2"
...
SSLCertificateFile /etc/apache2/ssl.crt/server2.crt
SSLCertificateKeyFile /etc/apache2/ssl.key/server2.key
...
</VirtualHost>
</IfDefine>
</IfDefine>
Vorteil: Man kann jedem Virtual Host eigene Keys und SSL-Zertifikate zuordnen.
Named-based Virtual Hosts
Es ist jedoch mit named-based Virtual Hosts zumindest möglich, Server mit verschiedenen DocumentRoot Verzeichnissen aufzusetzen . Allerdings wird dabei immer nur das SSL-Zertifikat des ersten Hosts verwendet, da der Host-Header erst nach dem SSL-Handshake ausgewertet wird (so dass es am Client ggf. eine Fehlermeldung gibt).
Die Konfig sieht dann so aus:
NameVirtualHost *:443
<IfDefine SSL>
<IfDefine !NOSSL>
<Directory "/srv/www/vhosts/server1">
Options None
AllowOverride AuthConfig
Order allow,deny
Allow from all
</Directory>
<Directory "/srv/www/vhosts/server2">
Options None
AllowOverride AuthConfig
Order allow,deny
Allow from all
</Directory>
<VirtualHost *:443>
...
DocumentRoot "/srv/www/vhosts/server1"
...
SSLCertificateFile /etc/apache2/ssl.crt/server1.crt
SSLCertificateKeyFile /etc/apache2/ssl.key/server1.key
...
</VirtualHost>
<VirtualHost *:443>
...
DocumentRoot "/srv/www/vhosts/server2"
...
SSLCertificateFile /etc/apache2/ssl.crt/server1.crt
SSLCertificateKeyFile /etc/apache2/ssl.key/server1.key
...
</VirtualHost>
</IfDefine>
</IfDefine>
SSL-Proxy
Das Problem mit mehreren IP-Adressen kann man umgehen, wenn man das Modul mod_rewrite einsetzt, um einen "SSL-Proxy" zu bauen. Siehe z.B. http://www.serversupportforum.de/forum/faqs-anleitungen/2558-howto-ssl-proxy.html.
Nachteil: Unschöne URLs.
mod_rewrite
siehe
- http://www.whoopis.com/howtos/apache-rewrite.html
- http://www.webhostgear.com/109.html
- http://www.pro-linux.de/news/2006/9325.html
- http://www.modrewrite.de/foren/ftopic82.html
- Workshop: Redirect und Modrewrite
Alle Zugriffe von Port 80 auf Port 443 (SSL) umleiten
RewriteEngine on
RewriteCond %{SERVER_PORT} =80
RewriteRule ^(.*) https://%{SERVER_NAME}%{REQUEST_URI}
bzw.
RewriteEngine on
RewriteCond %{SERVER_PORT} !^430$
RewriteRule ^(.*) https://%{SERVER_NAME}%{REQUEST_URI} [L,R]
oder
<VirtualHost *:80>
ServerAlias *
RewriteEngine On
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [redirect=301]
</VirtualHost>
Diese Konfig funktioniert auch im <Directory>-Kontext, um z.B. nur eine bestimmte URL umzuleiten. Die folgende Konfig leitet nur http://www.kruedewagen.de/path auf https://www.kruedewagen.de/path um (und alle Unterverzeichnisse):
Alias /path /usr/share/path
<Directory /usr/share/path/>
Options FollowSymLinks
RewriteEngine On
RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^(.*) https://%{SERVER_NAME}%{REQUEST_URI} [L,R]
</Directory>
Wenn man Zugriffe von Localhost (Port 80) nicht nach HTTPS umleiten will (z.B. bei Problemen mit MediaWiki Job Queue):
<VirtualHost *:80>
RewriteEngine On
RewriteCond %{REMOTE_HOST} !127.0.0.1$
RewriteCond %{REMOTE_HOST} !::1$
RewriteCond %{REMOTE_HOST} !192.168.1.9$
RewriteCond %{REMOTE_HOST} !2a2a:2b2b2:2c2c2::1$
RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^(.*) https://%{SERVER_NAME}%{REQUEST_URI} [L,R]
</VirtualHost>
Zugriff auf IP auf FQDN umleiten
Eingabe im Browser: http://1.2.3.4 , Ziel der Umleitung: https://www.example.com.
<VirtualHost 1.2.3.4:80>
ServerName www-ip.example.com
RewriteEngine On
# Redirect access by IP address
#RewriteCond %{SERVER_NAME} 1.2.3.4
#RewriteRule ^(.*) https://www.example.com/$1 [L,R]
# nur direkter Aufruf, nicht alle URLs
#RewriteCond %{HTTP_HOST} !^www.example.com$
#RewriteRule /.* https://www.example.com/ [R]
RewriteCond %{HTTP_HOST} !^www.example.com$
RewriteRule /.* https://www.example.com/$1 [R]
</VirtualHost>
Ein / am Ende der URL einfügen
RewriteEngine on
RewriteRule ^/url$ http://www.mydomain.de/url/ [R]
Logging
Um rewrite Logging einzuschalten (für gesamten Server oder auf Virtual Host Ebene):
RewriteEngine on
RewriteLog "/var/log/apache2/rewrite.log"
RewriteLogLevel 2
Aussperren
- Zugriff für User Agent (z.B. Bot bzw. Suchmaschine) verhindern
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} (bot1|bot2) [NC]
RewiteRule ^ - [L,R=403]
- IP Adressen aussperren: wie oben aber mittels RewriteCond auf IP setzen
RewriteCond %{REMOTE_ADDR} 1.2.3.4
Authentifizierung
Apache 2.2
Wenn man eine Basic-Authentifizierung für ein Verzeichnis eingerichtet hat, gilt das normalerweise auch für alle Unterverzeichnisse. Man kann jedoch die Abfrage von Username/Passwort für Unterverzeichnisse ausschließen mittels:
Allow from all
Satisfy Any
siehe:
- http://httpd.apache.org/docs/2.2/mod/core.html#satisfy
- http://www.bluestarweb.on.ca/htaccess.html
- http://webmaster.iu.edu/security_info/index.shtml
Mit der folgenden Konfiguration wird Authentifizierung nur für bestimmte IP-Ranges ausgeschaltet:
<Directory /path/>
AllowOverride None
Order allow,deny
Allow from 127
Allow from 192.168.0.0/16
Allow from 10.1.0.0/16
AuthType Basic
AuthName "Login"
AuthUserFile /path/to/htpasswd
Require user user1
Satisfy Any
</Directory>
Apache 2.4
Die Require-Direktiven werden nun im Modul mod_authz_core behandelt.
Änderung gegenüber Apache 2.2: Statt
Order allow,deny
Allow from all
verwendet man
Require all granted
Hinwiese:
- "Require all denied" ist i.d.R. als Default gesetzt, so dass "Require all granted" in jeder Directory-Direktive gesetzt werden muss, wenn ein Zugriff allgemein erlaubt sein soll.
- Eine Mischung der neuen Require-Direktiven mit "Allow/Deny from" sollte unbedingt vermieden werden.
Beispiele
Login nur mit Basic Auth:
<Directory "/srv/www/vhosts/myhost">
Options FollowSymLinks
AllowOverride None
Require all denied
AuthType Basic
AuthName "MyHost Login"
AuthUserFile /srv/www/passwdfile
<RequireAny>
Require user myuser
</RequireAny>
</Directory>
Erlaube Zugriff über IP-Ranges oder - falls man von anderer IP kommt - alternativ per Basic Auth:
<Directory "/srv/www/vhosts/myhost">
Options FollowSymLinks
AllowOverride None
Require all denied
AuthType Basic
AuthName "MyHost Login"
AuthUserFile /srv/www/passwdfile
<RequireAny>
Require ip 192.168
Require ip ::1
Require user myuser
</RequireAny>
</Directory>
Authentifizierung auf bestimmte Bereiche (Webseiten) beschränken mit FilesMatch-Direktive, z.B. bei Wordpress auf die Login- und Konfigurationsseite:
<Directory "/srv/www/vhosts/myhost">
Options FollowSymLinks
AllowOverride None
<FilesMatch "(wp-config.php|wp-login.php">
Require all denied
AuthType Basic
AuthName "MyHost Login"
AuthUserFile /srv/www/passwdfile
<RequireAny>
Require ip 192.168
Require ip ::1
Require user myuser
</RequireAny>
</FilesMatch>
</Directory>
TLS
SSL/TLS Zertifikate allgemein
- erstellt private Key mit Passphrase
openssl genrsa -des3 -out server.key 2048
- erstellt private Key ohne Passphrase
openssl genrsa -out server.key 2048
- erstellt Zertifikatssignierungsanfrage (CSR)
openssl req -sha256 -new -key server.key -out server.csr
- Zertifikatssignierungsanfrage (CSR) anzeigen
openssl req -in server.csr -noout -text
- erstellt selbstsigniertes Zertifikat
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
- Zertifikat anzeigen
openssl x509 -in server.crt -noout -text
Zertifikate für mehrere Namen
Die "alternativen Namen" müssen im CSR stehen! Dazu muss eine Konfiguration erstellt werden, z.B.
[ req_distinguished_name ] countryName = DE stateOrProvinceName = NRW localityName = Mettmann O = Example GmbH organizationalUnitName = IT commonName = www.example.com emailAddress = user@example.com [ v3_req ] basicConstraints = CA:FALSE subjectAltName = @alt_names [alt_names] DNS.1 = www.example.com DNS.2 = example.com
Dann CSR erstellen:
openssl req -sha256 -new -key server.key -out server.csr -config openssl.cnf
SSL/TLS Zertifikate unter openSUSE
Keys und CSR können mit folgendem Script aus dem Paket apache2-utils erzeugt werden:
/usr/bin/gensslcert
Vorgehen:
- Änderungen in /usr/bin/gensslcert vornehmen
- Schlüssellänge auf 4096 setzen
- Ggf. Email-Adresse aus dem CSR entfernen (je nach CA)
- "-sha256" als Option bei der Erzeugung des CSR hinzufügen
- Schlüssel und CSR erzeugen, z.B. für CAcert:
gensslcert -c DE -s NRW -l Mettmann -o "privat" -u "privat" -e "webmaster@kruedewagen.de" -n kruedewagen.de
- oder für StartSSL ("www" im CN-Feld):
gensslcert -c DE -s NRW -l Mettmann -o "privat" -u "privat" -e "webmaster@kruedewagen.de" -n www.kruedewagen.de
- ACHTUNG: Dieses Kommando überschreibt die server.* Dateien in /etc/apache2/ssl.*.
Server Name Indication (SNI)
Mehrere SSL-Server unter einer IP-Adresse.
Generatoren und Konfiguration erstellen
Zertifikate-Chain
Ab Apache 2.4.8 kann bzw. sollte die komplette Zertifikate-Chain (inkl. Server-Zertifikat, Intermediates, Root CA) in SSLCertificateFile angegeben werden.
- http://serverfault.com/questions/588986/sslcertificatechainfile-deprecation-warning-on-apache-2-4-8
- http://stackoverflow.com/questions/31370454/sslcertificatechainfile-is-obsolete
Performance Tuning
Siehe
- http://httpd.apache.org/docs/2.2/misc/perf-tuning.html
- http://httpd.apache.org/docs/2.4/misc/perf-tuning.html
- http://www.thomas-krenn.com/de/wiki/Apache_Performance_Tuning
Server-Einstellungen
Möglichst gute Settings:
StartServers 5
MinSpareServers 5
MaxSpareServers 10
ServerLimit 255
MaxClients 255
MaxRequestsPerChild 50000
KeepAlive On
MaxKeepAliveRequests 500
KeepAliveTimeout 15
Server Status
- Siehe http://httpd.apache.org/docs/2.2/mod/mod_status.html
- Modul mod_status laden
- Konfig
<IfModule mod_status.c>
<Location /server-status>
SetHandler server-status
Order deny,allow
Deny from all
Allow from localhost 127.0.0.1
</Location>
</IfModule>
ExtendedStatus On
- Zugriff über http:/server-status
Hinweis: "ExtendedStatus On" sollte nut temporär gesetzt sein.
Komprimierung und Cache Expiration
Die Module mod_deflate und mod_expires sollten geladen sein, unter Apache 2.4 auch das filter Modul. Zur richtigen Einrichtung der Komprimierung und der Ablauf-Zeiten, sollte folgende Konfig erstellt werden:
/etc/httpd/conf.d/deflate_expires.conf
Resultat:
- Der Server sollte in der Antwort zurücksenden:
Content-Encoding gzip
- Der Content ist mit den eingestellten Expiry Zeiten versehen, so dass das Caching auf der Client-Seite verbessert wird.
Weblinks:
- http://betterexplained.com/articles/how-to-optimize-your-site-with-gzip-compression/
- http://gtmetrix.com/enable-gzip-compression.html
- http://stackoverflow.com/questions/12367858/how-can-i-get-apache-gzip-compression-to-work
- http://tecadmin.net/how-to-enable-gzip-compression-on-apache/
- http://www.linux-faqs.info/apache/optimize-website-speed-with-mod-expire-and-mod-deflate
HTTP/2
In Apache HTTP/2 zusammen mit PHP-FPM, TLS 1.3 einrichten siehe Apache + HTTP2 + PHP-FPM + TLS 1.3.
Spezialitäten
Folgende Konfiguration ist nötig, falls Dateien von einem Samba-Share über Apache zugänglich gemacht werden sollen, ansonsten werden z.B. größere Dateien nicht vollständig transferiert (nur ca. 60 kByte):
<directory /path_to_dir>
EnableMMAP off
EnableSendfile off
</directory>
/path_to_dir ist das Verzeichnis, welches dann u.U. per symlink auf das Samba Share verweist.