LetsEncrypt – kostenloses SSL-Zertifikat auf dem Server

Vorwort

Lange habe ich überhaupt keinen Sinn und Zweck in Zertifikaten gesehen – geht ja auch ohne. Mittlerweile kommt man bei Facebook und Google als Seitenbetreiber nicht mehr um verschlüsselte Verbindungen herum. Wenn man es mal genau betrachtet … jede Seite auf der ich irgendetwas persönliches eingebe (Newsletter-Anmeldung, irgendwelche Login-Daten, usw.) sollte entsprechend meine Daten schützen, wir lassen uns ja auch bei der Eingabe der PIN am Bankautomat nicht über die Schulter gucken.

Meine ersten Zertifikate

Wie so ziemlich jeder, der irgendwann in die Welt der Zertifikate eintaucht, stand ich vor der ersten Hürde … sie kosten Geld. Einziger Ausweg waren damals self-signed-Zertifikate. Unter Linux kein großes Problem, schnell ist eins erstellt und muss dann in die jeweilige Serveranwendung eingebunden werden. Eine kleine „Ernüchterung“ stellt sich beim ersten Test der mit self-signed gesicherten Webseite schon ein … der Browser warnt uns, das es ein Zertifkat gibt, er aber nicht weiß, ob man ihm vertrauen kann. Das speichern einer Ausnahmeregel gestatten eigentlich alle Browser, so dass es uns nicht weiter belastet. Wenn man aber Dienste für möglicherweise unbekannte Dritte anbietet, ist das schon etwas störend.

Die Alternativen

Heute gibt es schon mehrere Anbieter, die kostenlose Zertifikate anbieten. Die Leistungen sind unterschiedlich, was Anzahl Domains, Gültigkeit und vor allem das Handling angeht. Es ist schon wenig komfortabel, wenn man alle 30 Tage sein Zertifikat manuell verlängern muss und dann auch in allen Anwendung neu einbinden muss.

Deshalb sticht der Anbieter LetsEncrypt heraus … er bietet kostenlose Zertifikate für bis zu 100 Domains und mit einer Laufzeit von 90 Tagen an. Der Clou … dank einer Software lässt sich das Renewal sogar automatisieren. Das macht es jetzt schon recht einfach seine Webseiten und Mailserver mit einem SSL-Zertifikat zu sichern.

Voraussetzungen

Wir kennen uns etwas mit Linux aus und wissen grundsätzlich, wie wir selbst Skripte erstellen und haben auch schon den Apache auf unserem Server selbst eingerichtet. Vielleicht haben wir auch schon mit self-signed-Zertifikaten gearbeitet, dann ist vor allem die Apache-Konfig mit SSL nichts Neues.

Ziel ist nun das Ganze mit einem LetsEncrypt-Zertifikat zu versehen, dass sich selbst aktualisiert. Die folgenden Schritte sollten unter Ubuntu 14/16 und Raspbian Wheezy/Jessie funktionieren. Python muss auch installiert sein, da der Certbot darauf aufbaut.

Das Setup

Zuerst müssen wir den so genannten Certbot laden und installieren, der für uns das Zertifikat anfordern und aktualisieren kann …

root@server:~# wget https://dl.eff.org/certbot-auto
root@server:~# mkdir /usr/local/sbin/certbot
root@server:~# mv ./certbot-auto /usr/local/sbin/certbot/

Damit haben wir nun den Certbot betriebsbereit auf dem System. Er bietet viele Automatisierungen für das Ausstellen des Zertifikates und sogar für das Konfigurieren von Apache an. Letzteres habe ich nie ausprobiert, da ich es nicht so gerne mag, wenn irgendwer in meinen Konfigurationen Sachen ändert. Gerade, wenn man ein komplexes Gebilde mit verschiedenen SNI-basierten VirtualHosts hat und vielleicht auch noch mehrere Zertifikate verwaltet, traue ich dabei keinem Automatismus.

Zertifikat ausstellen

Ich habe mir dafür ein Skript in /usr/local/sbin/certbot-sign.sh erstellt. Wenn ich die Domains im Zertifikat ändern muss, dann gebe ich die Änderung in der Datei ein und weiß so immer, was im Zertifikat sein sollte.

#!/bin/bash
/usr/local/sbin/certbot/certbot-auto certonly --standalone --rsa-key-size 4096 -d server.tld -d mail.server.tld -d ssl.server.tld --pre-hook "service apache2 stop" --post-hook "service apache2 start"

Das Skript wird als root gestartet und startet den Certbot ohne Konfigurationsskript (–standalone) und fordert EIN Zertifkat für ALLE Domains, die jeweils mit -d angegeben werden. Der Apache wird gestoppt und im Anschluss wieder gestartet (–pre-hook / –post-hook), denn der Certbot braucht den Port 80, damit bei der Zertifikaterstellung geprüft werden kann, ob denn der Server auch wirklich unter dem Domainnamen erreicht werden kann.

Wenn ich eine neue Domain hinzufüge, schreibe ich ein weiteres -d einfach vor das –pre-hook und starte es manuell per sudo. Das Zertifikat wird dann neu erstellt. Das Löschen einer Domain geht auf diesem Wege auch. Wissenswert ist, dass die erste Domain der Stammname für das Zertifikat ist, womit der Certbot unter /etc/letsencrypt die Zertifikate und eine Konfig anlegt.

Einbinden im Apache

Das Einbinden im Apache ist recht einfach. Wenn nicht schon geschehen, weil ein self-signed-Zertifikat eingesetzt wurde, muss das Modul mod_ssl installiert und im Apache geladen sein.

Dann braucht es eine Grundkonfig für mod_ssl, damit das Zertifikat schon bei der ersten Verbindung zum Apachen zur Verfügung steht. Bei mir sieht es in /etc/apache2/sites-available/default-ssl.conf so aus …

<IfModule mod_ssl.c>
	<VirtualHost _default_:443>
		ServerAdmin webmaster@server.tld
		DocumentRoot /var/www/html

		SSLEngine On
		SSLCertificateFile      /etc/letsencrypt/live/server.tld/fullchain.pem
		SSLCertificateKeyFile   /etc/letsencrypt/live/server.tld/privkey.pem

		<FilesMatch "\.(cgi|shtml|phtml|php)$">
						SSLOptions +StdEnvVars
		</FilesMatch>

		<Directory /usr/lib/cgi-bin>
						SSLOptions +StdEnvVars
		</Directory>

		BrowserMatch "MSIE [2-6]" \
						nokeepalive ssl-unclean-shutdown \
						downgrade-1.0 force-response-1.0

		# MSIE 7 and newer should be able to use keepalive
		BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
	</VirtualHost>
</IfModule>

Jetzt müssen wir noch den einzelnen Webseiten eine Konfiguration für SSL verpassen. Wir nehmen an, dass wir einen VirtualHost unter ssl.server.tld in der Datei ssl.conf eingerichtet haben …

<VirtualHost *:80>
	ServerName ssl.server.tld
	ServerAdmin webmaster@server.tld
	DocumentRoot /var/www/ssl

	RewriteEngine On
	RewriteCond %{HTTPS} off
	RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]   ## umleiten auf ssl

	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined

</VirtualHost>

<VirtualHost *:443>
	ServerName ssl.server.tld
	ServerAdmin webmaster@server.tld
	DocumentRoot /var/www/ssl

	SSLEngine On
	SSLCertificateFile      /etc/letsencrypt/live/server.tld/cert.pem
	SSLCertificateKeyFile   /etc/letsencrypt/live/server.tld/privkey.pem
	SSLCertificateChainFile /etc/letsencrypt/live/server.tld/chain.pem

</VirtualHost>

<Directory /var/www/domain1>
	Options FollowSymLinks
	AllowOverride None
	Order deny,allow
	Require all granted	
</Directory>

Die im oberen Block für Port 80 eingefügten Rewrite-Optionen bewirken, dass auch Besucher auf dem Port 80 auf den SSL-Port 443 umgeleitet werden. Wir lassen also keine ungesicherte Kommunikation mehr zu.

Jetzt noch den Apache neu starten und es sollte dann die Seite ssl.server.tld mit https: und einem gültigen Zertifikat erscheinen.

Zertifikat aktuell halten

Hier werden uns ein weiteres Skript und ein Eintrag im Crontab helfen. Theoretisch müsste man das Renewal nur exakt 90 Tage nach dem letzten lauf durchführen. Seien wir ehrlich … so wird es keiner machen. Zuerst das Skript in /usr/local/sbin/certbot-renew.sh anlegen …

#!/bin/bash
/usr/local/sbin/certbot/certbot-auto renew --standalone --pre-hook "service apache2 stop" --post-hook "service apache2 start"

Alte Bekannte sind die hooks … die wieder den Apache kurzzeitig abschalten. Da sich der Certbot die Domains im Zertifikat unter /etc/letsencrypt gemerkt hat, brauchen wir sie hier nicht angeben.

Das Skript schreiben wir jetzt in /etc/crontab so dass es regelmäßig das Wohl unseres Zertifikates pflegt …

[...]
@weekly         root    /usr/local/sbin/certbot-renew.sh
[...]

Warum lasse ich den Job nun wöchentlich (d.h. Sonntags 0 Uhr) erledigen? Theoretisch würde monatlich ja auch reichen, aber ich hatte folgende Rechnung:

  • ich erstelle mein Zertifikat am 1. des Monats
  • @monthly läuft am Monatsersten 0:00 Uhr
  • beim ersten Lauf von certbot-renew.sh ist das Zertifikat noch 60 Tage gültig
  • beim zweiten Lauf noch 30 Tage – da macht der certbot von sich aus noch keine Neuanforderung, macht er erst bei 15 Tagen
  • beim dritten Lauf ist es jetzt der Ablauftag. Geht nun irgendwas schief, sehe ich morgens zwar die Fehlermeldung in meinem Posteingang, habe aber im ungünstigsten Fall schon ein abgelaufenes Zertifikat.

Also lasse ich wöchentlich prüfen. Das dauert nur ein paar Sekunden und dem Apache schadet ein wöchentlichen Neustart auch nicht. Soweit mein Setup für den Apache mit LetsEncrypt.

meine Erfahrung mit LetsEncrypt

Ich bin ein Fan von diesen Zertifkaten geworden und habe das System auf verschiedenen Rechnern laufen. Bisher hatte ich nur einmal das Problem, dass ich beim „re-sign“ (also das Hinzufügen einer Domain) die neue Domain an den Anfang der Kette geschrieben habe und dann ein neues Zertifikat mit einer neuen Stammdomain hatte.

Das ist aber kein unlösbares Problem. Mit dem Befehl

root@server:~# /usr/local/sbin/certbot/certbot-auto certificates

erhält man eine Übersicht der Zertifikate. In dieser Übersicht sieht man neben dem Stammnamen (den brauchen wir) auch die Restgültigkeit und den Speicherort. Das zu löschende Zertifikat kann man dann mit dem Befehl

sudo /usr/local/sbin/certbot/certbot-auto delete --cert-name server.tld

vom System entfernen.

Weitere Anwendungen

Ich setze die Zertifikate auch im Mailserver postfix/dovecot ein. Die Konfiguration habe ich auf Basis des Blog von Thomas Leister erstellt.

Links