Apache

aus www.kruedewagen.de, Homepage von Ralf und Judith Krüdewagen (Kruedewagen)
Zur Navigation springen Zur Suche springen

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

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:

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.

Performance Tuning

Siehe

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

<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

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/2

In Apache HTTP/2 zusammen mit PHP-FPM, TLS 1.3 einrichten siehe Apache + HTTP2 + PHP-FPM + TLS 1.3.

HTTP/2 Testseiten:

Spezialitäten

Samba Share

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.

Dokumentation

Siehe auch