Laut Dokumentation unterstützt Apache mit SSL keine Vhosts, da Vhosting auf Grundlage des HTTP-Headers funktioniert und SSL ein Layer drunter liegt und die Verbindung bereits sichert, bevor nur ein Byte HTTP-Protokoll gesprochen ist.
Man kann es trotzdem nutzen, muss dafür aber ein paar Dinge tun.
Pro IP brauch man
1 SSL-Zertifikat, in dem alle Hostnamen, die auf die IP zeigen, angegeben sein müssen. Für Subdomains braucht man entweder ein
Wildcardzertifikat oder man muss alle existierenden Hostnamen eintragen. Solche Zertifikate gibt es z.B. bei
CaCert. Dazu muss man sich einen
CSR erzeugen und auf der Webseite hochladen.
Um Zertifikate mit mehreren Hostnamen zu erstellen, muss man das Attribut
subjectAltName benutzen.
Zum Erstellen mit OpenSSL brauch man eine
openssl.cf. Die wichtigsten Einträge dafür:
[ req ]
distinguished_name = req_distinguished_name
req_extensions = v3_req
[ req_distinguished_name ]
commonName = Common Name (eg YOUR name)
commonName_default = domain.de
[ v3_req ]
subjectAltName = DNS:*.domain.de
Erstellt wird der CSR mit dem Aufruf:
openssl req -new -key domain.de.key -days 730 -nodes -out domain.de.csr -config openssl.cf
Das erzeugt einen Request für ein Wildcardzertifikat für
domain.de.
Mit der Option
-x509 kann man sich das Zertifikat gleich selbst signieren, wenn man keinen Acocunt bei CaCert oder einer anderen CA hat.
[Update: Damit die Extension mit dem
subjectAltName auch im selbstsignierten Zertifikat erscheint, muss man statt
req_extensions = v3_req
x509_extensions = v3_req
angeben, da hier ja kein CSR erstellt wird.
]
Weitere Infos zum Erzeugen solcher CSRs findet man in der
CaCert-Wiki bzw. in den Manpages zu
req und
config aus dem OpenSSL-Paket.
Das unterschriebene Zertifikat legt man dann z.B. in /etc/apache2/ssl/domain.de.crt ab.
Entscheidend ist dann die Kofiguration des Default-Host. Weit verbreitet sind folgende Einstellungen:
Listen *:443
NameVirtualHost *:443
<VirtualHost *:443>
ServerName www.domain.de
SSLEngine on
SSLCertificateFile /etc/apache2/ssl/domain.de.crt
SSLCertificateKeyFile /etc/apache2/ssl/domain.de.key
</VirtualHost>
<VirtualHost *:443>
ServerName subdomain.domain.de
</VirtualHost>
Da
mod_ssl nichts mit Vhosts anfangen kann, benutzt es die SSL-Einstellungen des ersten Vhost mit der IP-Port-Kombination auch für alle weiteren entsprechenden Vhosts. Dem obigen Beispiel folgend, würde auch die Verbidung zu
subdomain.domain.de verschlüsselt.
Dies ist für fast alle Anwendungen ausreichend. Mit einem Wildcardzertifikat sind dann auch die meisten Browser schweigsam, was die Zertifikatsprüfung angeht.
Auf Serverseite kann dies aber zu Problemen führen. Denn, bis auf den Defaultvhost, fehlt allen anderen mit passenden IP-Port-Tupeln die
SSLEngine-Direktive, was den Apache glauben lässt, sie nutzten nur unverschlüsselte Verbindungen.
Ohne sie kann man jedoch z.B. in PHP nicht mehr feststellen, ob die SSL-Verschlüsselung aktiviert ist.
Richtig nervig wird es dann mit
WebDAV für z.B. SVN, was ich in einem
anderen Eintrag beschrieben habe.
Versucht man die Direktive für alle weiteren Vhosts zu setzen, verweigert der Apache komplett seinen Dienst.
Es gibt aber Abhilfe.
Namenlos beschreibt in einem älteren Artikel einen Workaround für Vhosting mit SSL. Dabei wird die Zertifikat- und Schlüsselangabe außerhalb der Vhost-Kofiguration gemacht:
Listen *:443
NameVirtualHost *:443
SSLCertificateFile /etc/apache2/ssl/domain.de.crt
SSLCertificateKeyFile /etc/apache2/ssl/domain.de.key
<VirtualHost *:443>
ServerName www.domain.de
SSLEngine on
</VirtualHost>
<VirtualHost *:443>
ServerName subdomain.domain.de
SSLEngine on
</VirtualHost>
Erstaunlicherweise ist es dann möglich in mehreren Vhosts die SSLEngine-Direktive zu nutzen.
Das funktioniert so aber nur mit einem Zertifikat. Wichtig ist noch: Das
mod_ssl findet nun für eine IP-Port-Kombination 2 Hostnamen und meckert im Logfile, dass man Vhosting nicht unterstütze:
[warn] Init: SSL server IP/port conflict: domain.de:443 (/etc/apache2/sites-enabled/00default:45) vs. subdomain.domain.de:443 (/etc/apache2/sites-enabled/01domain.de:13)
[warn] Init: You should not use name-based virtual hosts in conjunction with SSL!!
Leider erkennt es nicht, dass das hier zweimalig verwendete Zertifikat beide Hostnamen abdeckt. Aber ich denke, damit kann man leben, so lange es trotzdem funktioniert.
Zeigen nun 2 oder mehr IPs und dazugehörige Domains auf den Server, muss man einen Schritt weiter gehen. Für jede IP sollte man ein extra Zertifikat haben, damit man nicht in Schwierigkeiten gerät, wenn man eine IP abgibt bzw. hinzufügt.
Mit Probieren bin ich auf folgende für mich funktionierende Konstruktion gekommen:
Listen *:443
NameVirtualHost *:443
SSLCertificateFile /etc/apache2/ssl/domain.de.crt
SSLCertificateKeyFile /etc/apache2/ssl/domain.de.key
<VirtualHost 10.10.10.1:443>
ServerName domain1.de
SSLEngine on
SSLCertificateFile /etc/apache2/ssl/domain1.de.crt
SSLCertificateKeyFile /etc/apache2/ssl/domain1.de.key
</VirtualHost>
<VirtualHost 10.10.10.1:443>
ServerName subdomain.domain1.de
SSLEngine on
</VirtualHost>
<VirtualHost 10.10.10.2:443>
ServerName domain2.de
SSLEngine on
SSLCertificateFile /etc/apache2/ssl/domain2.de.crt
SSLCertificateKeyFile /etc/apache2/ssl/domain2.de.key
</VirtualHost>
<VirtualHost 10.10.10.2:443>
ServerName subdomain.domain2.de
SSLEngine on
</VirtualHost>
Tatsächlich lässt sich im Defaultvhost für jede IP der Pfad zu Zertifikat und Schlüssel überschreiben. In diesem Fall kann das oben eingestellte Zertifikat-Schlüssel-Paar sogar ein Dummy sein, da es für jede IP neu gesetzt wird.
In den ungeordneten Vhosts reicht dann das schon genannte
SSLEngine On.
Damit ist es möglich, auf einem Server mit mehreren IPs und seperaten Vielhost- oder Wildcardzertifikaten Vhosting zu betreiben.
...wenn man über die paar Zeilen Fehlermeldung beim Serverstart hinweg sehen kann.
PS: Für diesen Artikel kamen
Apache/2.2.3 (Debian) DAV/2 SVN/1.4.2 mod_ssl/2.2.3 OpenSSL/0.9.8c configured zum Einsatz.