Let’s Encrypt Zertifikat in nginx auf dem Raspberry Pi
Let’s Encrypt hat sich in wenigen Monaten zu einer zuverlässigen, kostenlosen und weit verbreiteten Lösung für kostenlose SSL-Zertifikate gemausert. Wenn man auf einem Raspberry Pi einen Webserver betreibt, lohnt sich der geringe Aufwand für eine grüne HTTPS-URL.
Obwohl dieser Artikel mit Sicherheit nicht der erste (und auch nicht der letzte) Artikel zu Let’s Encrypt auf dem Raspberry Pi ist, hat dieser Artikel durchaus seine Daseinsberechtigung. Ein Großteil der verfügbaren deutschen Artikel sind unvollständig, gehen auf gewisse Aspekte nicht ein oder gehen von dem reinen Standardfall “Apache mit Authentifizierung über den Port 80” aus. Ich beziehe mich in diesem Artikel auf einen Raspberry Pi mit dem alten, aber dennoch weit verbreiteten Raspbian-Wheezy. Gleichzeitig verwende ich nginx als Webserver und nutze für die Authentifizierung des ACME-Bots nicht den Port 80 sondern den Port 443. Dies macht aus meiner Sicht auch viel mehr Sinn, weil man will ja gerade den HTTPS-Port, also Port 443, absichern und gerade nicht dauerhaft den Port 80 geöffnet halten.
Aber genug der Vorrede. Legen wir los.
Schritt 1: Grundsystem Raspbian Wheezy aktualisieren
Ausgangslage ist wie bereits gesagt ein Raspbian-Wheezy, wobei das System auf dem neuesten Stand sein sollte. Die notwendigen Befehle zur Aktualisierung sind:
apt-get update apt-get upgrade
Wichtig: Diese und alle folgenden Befehle werden mit Root-Rechten ausgeführt.
Schritt 2: Voraussetzungen installieren
Als nächstes kommen die folgenden Befehle, die ich im Nachgang erklären werde:
gpg --keyserver pgpkeys.mit.edu --recv-key 8B48AD6246925553 gpg -a --export 8B48AD6246925553 | sudo apt-key add - gpg --keyserver pgpkeys.mit.edu --recv-key 7638D0442B90D010 gpg -a --export 7638D0442B90D010 | sudo apt-key add - apt-get install -y python python-dev gcc dialog libssl-dev libffi-dev ca-certificates augeas-lenses libaugeas0 python-virtualenv cd /usr/local/bin git clone https://github.com/certbot/certbot
Mit den ersten vier Zeilen fügt man die PGP-Schlüssel von zwei sogenannten Backports von Raspbian Jessy dem System hinzu. Konkret geht es um die zwei Pakete libaugeas0 und augeas-lenses. Diese Pakete sind zwar in Raspbian Wheezy enthalten, liegen aber leider nicht in einer ausreichend neuen Version vor. Beim ersten Start des ACME-certbots versucht dieser, die passenden Pakete zu installieren und es kommt zum folgenden Fehler:
GPG-Fehler: http://http.debian.net wheezy-backports Release: Die folgenden Signaturen konnte nicht überprüft werden, weil ihr öffentlicher Schlüssel nicht verfügbar ist: NO_PUBKEY 8B48AD6246925553 NO_PUBKEY 7638D0442B90D010. To use the Apache Certbot plugin, augeas needs to be installed from wheezy-backports.
Diesem Fehler kann man mit den ersten vier Zeilen vorbeugen, indem man die zwei entsprechenden Server in die Liste der vertrauenswürdigen Server aufnimmt.
Mit der fünften Code-Zeile installiert man ein paar Pakete, die für die Nutzung und die Installation des certbots notwendig sind. Der Parameter -y führt dazu, dass die Pakete nicht noch einmal extra bestätigt werden müssen und die Installation sofort startet.
Als letztes holt man noch den certbot von Github. Diesen “clonen” wir in das Verzeichnis /usr/local/bin/certbot. Natürlich kann der certbot auch an eine andere Stelle kopiert werden, jedoch ist /usr/local/bin durchaus ein Verzeichnis, in dem man solche eigenen und lokalen Programme erwarten würde.
Schritt 3: Prüfen der Voraussetzungen
Um erfolgreich ein Let’s Encrypt Zertifikat zu beantragen, müssen ein paar Voraussetzungen erfüllt sein. Diese Voraussetzungen sollte man vorab sorgfältig prüfen, da nach fünf fehlgeschlagenen Anträgen eine Domain bzw. eine Subdomain für eine Woche von der Let’s Encrypt Authority gesperrt wird. Natürlich kann man zuerst mit einem Test-Server von Let’s Encrypt arbeiten, aber ich empfehle, dass man seine Hausaufgaben macht, bevor man irgendwie im Trial-And-Error Verfahren versucht, sich ein SSL-Zertifikat zu holen. Hier also die Voraussetzungen:
- es muss ein CNAME-Eintrag von der gewünschten Subdomain (z.B. cloud.ionas-server.com) auf die DynDNS-Adresse des eigenen Internetanschlusses zeigen,
- es muss eine Portweiterleitung im Router für den Port 443 auf den Zielserver eingerichtet sein,
- sollte eine eigene Firewall (z.B. iptables oder ufw) auf dem des Zielserver installiert sein, muss diese externe Zugriffe auf dem Port 443 erlauben.
Der erste Eintrag klingt erstmal kompliziert, sollte aber jemanden mit dem Wunsch nach einem eigenen Let’s Encrypt Zertifikat nicht abhalten. Was ist also zu tun? Ich gehe davon aus, dass ein Zertifikat für einen Raspberry Pi an einem Internetanschluß mit dynamischer IP-Adresse beantragt werden soll. Für diesen Fall empfehle ich einen kostenlosen Account bei spdyn.de. Dort kann man einen beliebigen Host wie zum Beispiel ich-will-lets-encrypt.spdns.org auf die IP-Adresse des eigenen Internetanschlusses legen. Natürlich sollte man beim Einsatz eines solchen DynDNS-Dienstes nicht vergessen, einen entsprechenden DynDNS-Client auf dem Raspberry Pi zu betreiben. Wir nutzen auf unseren ionas-Servern für diese Aufgabe die Software ddclient, damit diese Weiterleitung der spdyn-Adresse auf die eigene IP immer korrekt bleibt.
Sobald man den eigenen spdns-Account hat, legt man einen CNAME Eintrag für die eigene Domain an. In den Voraussetzungen habe ich zum Beispiel cloud.ionas-server.com verwendet, welches nun auf ich-will-lets-encrypt.spdns.org zeigt.
Diese Voraussetzung lässt sich nun ganz einfach prüfen. Man öffnet ein Terminal oder eine Shell und vergleicht das Ergebnis der folgenden beiden Befehle:
ping ich-will-lets-encrypt.spdns.org ping cloud.ionas-server.com
Es ist schon ziemlich offensichtlich, dass diese beiden Befehle das gleiche Ergebnis liefern sollten. Wenn Sie das nicht tun, dann braucht es vielleicht noch ein paar Minuten, bis der CNAME-Eintrag wirklich bei jedem NAME-Server im Internet angekommen ist. Wenn das nicht so ist, man hat vermutlich irgendwo entlang der Strecke einen Fehler gemacht.
Die nächsten beiden Anforderungen sind selbsterklärend. Der Router muss eingehende Anfragen auf dem Port 443 zum Raspberry Pi weiterleiten. Dies macht man in der weit verbreiteten Fritzbox unter Internet -> Freigaben -> Portweiterleitungen. In anderen Routern lauten die Navigationspunkte ähnlich.
Als letzte Anforderung muss eine ggf. installierte Firewall auf dem Raspberry Pi entsprechend geöffnet werden, damit Anfragen nicht von der Firewall direkt verworfen werden.
Schritt 4: Let’s Encrypt Zertifikat beantragen
Nun ist es wirklich nur noch ein Befehl, um das Let’s Encrypt Zertifikat zu beantragen. Dieser Befehl lautet:
/usr/local/bin/certbot/certbot-auto certonly --quiet --pre-hook "service nginx stop" --post-hook "service nginx start" --standalone -n --rsa-key-size 4096 --agree-tos -m email@example.com -d cloud.ionas-server.com --standalone-supported-challenges tls-sni-01
Natürlich muss die E-Mailadresse und die gewünschte Domain entsprechend angepasst werden. Hier nun die Erklärung zum Befehl:
- certonly: es wird nur das Zertifikat beantragt und keine automatische Änderung am Webserver vorgenommen.
- quiet: jeder Output bis auf Fehlermeldungen wird unterdrückt. Wenn man dieses Flag nicht setzt, wird man schier erdrückt an Rückmeldungen.
- pre-hook und post-hook: bevor der Befehl ausgeführt wird, wird der nginx-Webserver gestoppt und danach wieder gestartet. Dies ist notwendig, damit der ACME-Bot auf dem Port 443 nach der Rückmeldung der Let’s Encrypt Authority horchen kann.
- standalone: ich verwende bewußt standalone als Authentifizierungs-Plugin, da nur mit diesem die Authentifizierung über den Port 443 mit nginx möglich ist.
- rsa-key-size: definiert die Länge des Schlüssels, wobei man definitiv nicht weniger als 2048 verwenden sollte. Ich empfehle lieber 4096.
- agree-tos: es wird automatisch die ACME Subscriber Agreement akzeptiert.
- -m EMAIL: an diese E-Mailadresse geht eine Benachrichtigung sollte das Let’s Encrypt Zertifikat kurz vor dem Ablaufdatum stehen. Soweit sollte es niemals kommen, trotzdem sollte hier eine gültige E-Mailadresse angegeben werden.
- -d DOMAIN: für diese Domain wird ein Zertifikat angefordert und auf dieser Domain horcht auch der ACME-Bot.
- standalone-supported-challenges tls-sni-01: sorgt für eine Anfrage auf dem Port 443.
Eine vollständige Liste der Parameter findet man übrigens in der sehr guten Dokumentation von certbot.eff.org.
Sobald der Befehl eingetippt und bestätigt ist, fängt der ACME-Bot mit der Arbeit an. Der ganze Vorgang wird unter Raspbian Wheezy mindestens 15 Minuten dauern. Besonders wenn Sie die folgenden Ausgabe sehen, können Sie eine ausgiebige Kaffeepause einlegen:
creating virtual environment installing Python packages
Wenn der ganze Vorgang erfolgreich abgeschlossen wurde, werden Sie mit gültigen SSL-Zertifikaten unter /etc/letsencrypt/live/ belohnt. Um nun die Zertifikate im nginx-Webserver einzubinden, passen Sie die entsprechende nginx-Datei unter /etc/nginx/sites-available/ an:
ssl on; ssl_certificate /etc/letsencrypt/live/cloud.ionas-server.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/cloud.ionas-server.com/privkey.pem;
Schritt 5: Regelmäßige Aktualisierung des Zertifikats per Cronjob
Genauso wichtig wie die Beantragung des Let’s Encrypt Zertifikats ist die regelmäßige Aktualisierung. Let’s Encrypt Zertifikate sind immer nur drei Monate gültig und sollten gemäß Empfehlung der Let’s Encrypt Authority täglich aktualisiert werden. Der certbot erkennt nämlich automatisch wie lange das Zertifikat noch gültig ist und legt sich bei einer langen Gültigkeit einfach wieder schlafen. Nur wenn das Zertifikat innerhalb der nächsten 30 Tage abläuft, aktualisiert der acme-Bot das Zertifikat. Da sich der Dateiname des aktualisierten Zertifikats nicht ändert, müssen Sie an der Webserverkonfiguration nichts ändern.
An dieser Stelle kommt nun der große Vorteil von einer Prüfung auf dem Port 443 ins Spiel. Das Zertifikat wurde ja bewusst beantragt, um abgesichertes HTTPS zu nutzen. Der Port 443 ist so oder so geöffnet. Der Standardport 80 für die Beantragung und Aktualisierung muss nicht geöffnet werden.
Mit dem folgenden Cronjob wird täglich das Zertifikat überprüft und bei Bedarf erneuert. Die Prüfung wurde ganz bewußt auf 4 Uhr morgens gelegt, um die Auswirkungen eines kurzfristigen Stop des Webservers so gering wie möglich zu halten.
0 4 * * * /usr/local/bin/certbot/certbot-auto renew --standalone --pre-hook "service nginx stop" --post-hook "service nginx start" >> /var/log/letsencrypt/letsencrypt.log
Mit wenig Aufwand und der richtigen Vorbereitung lässt sich auch unter Raspbian Wheezy ein SSL-Zertifikat von Let’s Encrypt mit dem nginx-Webserver nutzen. Sollten Sie Fragen oder Probleme haben, dann zögern Sie nicht uns zu schreiben oder uns anzurufen.
Natürlich freuen wir uns auch über einen Like auf unserer Facebook-Seite oder ein paar nette Worte in Google Business.