Wildcard-Zertifikate von Letsencrypt mit DNS-Abfrage

Betreibt man mehrere Web-Anwendungen auf einem eigenen Server, ist es relativ lästig für jede einzelne Subdomain einen eigenen Prozess am Laufen zu halten, der das jeweils benötigte SSL-Zertifikat immer rechtzeitig vor Ablaufdatum holt und den Verifizierungsprozess über die eigene Website durchführt.

Aus diesem Grund gibt es Wildcard-Zertifikate, also Zertifikate, die in einem Zertifikat die eigene Domain inklusive aller Subdomains abdeckt. Dieses Zertifikat kann man dann zentral ablegen und ohne weitere Aktionen für alle Subdomains nutzen. Wie man das macht, erkläre ich jetzt.

Vorraussetzungen

Konfiguriere Deinen DNS-Server so, dass die alle Deine Sub-Domains auf die IP-Adresse Deines zentralen Webserver zeigen und die Anfragen von Nutzern so überhaupt erst einmal bei Dir landen. Ebenso muss der DNS Deines Providers die Möglichkeit bieten über eine API Texteinträge zu generieren, die im Verifikationsprozess abgefragt werden können.

Zunächst müssen wir uns das Skript acme.sh besorgen, mehr dazu weiter unten. Da wir unser Script zentral installieren wollen, tun wir dies als User root:

sudo -s
wget -O acme.sh https://get.acme.sh

Alternativ können wir das auch mit Git holen, wenn installiert:

git clone https://github.com/Neilpang/acme.sh.git
cd acme.sh

Installation

Wir nutzen hier für das Abholen und erzeugen der Zertifikate das Script acme.sh von Neil Pang, welches auf Github näher erklärt ist: https://github.com/Neilpang/acme.sh . Dieses Script hat gegenüber Certbot den Vorteil, dass es keine Python-Installation benötigt und stattdessen in Shell geschrieben ist. Es läuft auf jedem Linux-System und sogar auf Windows (wer es mag). Das Ablegen von Zertifikaten kann ganz einfach und individuell konfiguriert werden.

Wir möchten unser Script bzw. die später erzeugten Zertifikate zentral unter /etc/acme.sh installieren, der eigene Account-Schlüssel bleibt beim User root:

sudo ./acme.sh --install \
--home /etc/acme.sh \
--config-home /etc/acme.sh/config \
--cert-home  /etc/acme.sh/certs \
--accountemail  "admin@datenbrei.de" \
--accountkey  ~/.acme/myaccount.key \
--accountconf ~/.acme/myaccount.conf 

Das Script erzeugt auch gleich einen Cron-Job, damit später die Zertifikate regelmäßig und automatisch erneuert werden. Ansehen kann man das als User root mit crontab -l.

DNS-Zugriff konfigurieren (wenn möglich)

Um Zertifikate anfordern zu können, muss der benutzte DNS über eine API und ein Passwort angefragt werden können. Um diese Einstellungen dem acme.sh mitzuteilen, werden nun vor dem eigentlichen Abholen der Zertifikate einige Umgebungsvariablen gesetzt. Dies muss nur einmalig gemacht werden, acme.sh merkt sich dies in seiner Konfiguration:

Beispiel für den DNS von Netcup:

export NC_Apikey="<Apikey>"
export NC_Apipw="<Apipassword>"
export NC_CID="<Customernumber>"

Beispiel für den DNS von Cloudflare:

export CF_Key="Apikey"
export CF_Email="xxxx@sss.com"

Weitere DNS-Einstellungen können hier eingesehen werden, das ist hier hervorragend dokumentiert:

https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api

Selbstverständlich muss provider-seitig die Abfrage des DNS über die APIvorab freigeschaltet sein.

Abholen der Zertifikate (automatisch)

Nachdem alle Vorarbeiten gemacht sind, können nun die Zertifikate abgeholt werden, wieder an unseren zwei Beispielen. Dabei holen wir Zertifikate sowohl für die Domain selber, hier meinedomain.de, wie auch die jeweiligen Subdomains, die wir später möglicherweise nutzen wollen. Wir setzen dabei die DNS-Antwortzeit etwas hoch, da einige DNS-Server länger bruachen, um den neuen Texteintrag tatsächlich zur Verfügung zu stellen. Ich habe gute Erfolge mit 480 Sekunden Wartezeit erzielt.

Für den DNS von Netcup:

./acme.sh --issue --dnssleep 480 --dns dns_netcup -d 'meinedomain.de' -d '*.meinedomain.de'

Für den von Cloudflare:

./acme.sh --issue --dnssleep 480 --dns dns_cf -d 'meinedomain.de' -d '*.meinedomain.de'

Abholen der Zertifikate (händisch)

Kann ein DNS nicht automatisch abgefragt werden, weil man keinen Zugriff auf die API hat, ist es möglich, die Text-Einträge selber händisch vorzunehmen. Das muss aber jedesmal beim Erneuern der Zertifikate wieder stattfinden. Daher ist diese Lösung im Grunde nicht praktikabel. Wir wollen ja möglichst alles automatisieren. Will man es trotzdem, kann man das so machen:

acme.sh --issue -d 'meinedomain.de' -d '*.meinedomain.de' --dns --dnssleep 960 --yes-I-know-dns-manual-mode-enough-go-ahead-please

Probleme?

Gibt es Probleme, kann man den Prozess mit den Optionen --log oder --debug weiter analysieren. Das größte Problem ist das Timeout. Hier sollte man ggf. den Wert von --dnssleep erhöhen.

Ergebnis

Wir haben nun unsere neuen Zertifikate im Verzeichnis /etc/acme.sh/certs. Wir können diese nun in die jeweiligen Server-Konfigurationen von Apache oder Nginx einbinden. Ich selbst nutze Nginx (als Reverse Proxy):

# Let's Encrypt SSL
ssl_certificate     /etc/acme.sh/certs/meinedomain.de/fullchain.cer;
ssl_certificate_key /etc/acme.sh/certs/meinedomain.de/meinedomain.de.key;

Da sich die Zertifikate erneuern, ohne, dass der Webserver dafürbenötigt wird (wir nutzen ja die DNS-API), ist auch die Konfiguration des Webservers wesentlich einfacher. Es muss kein Mechanismus für das Abfangen der Letsencrypt-Challenges eingerichtet sein und Port 80 kann zu bleiben, wenn gewünscht.