Let’s Encrypt via acme.sh für Apache und Nginx
Ende 2015 bin ich auf das Thema Webserver SSL Optimierung: HSTS und HPKP eingegangen. Nun möchte ich euch ein kleines Update zu Let’s Encrypt mit dem acme.sh Script für Apache und Nginx geben. Die Anleitung basiert auf dem ACME Webroot Verfahren, ein Stoppen des Webservers wie beim Standalone Verfahren ist nicht nötig.
Punkt 1: Apache Webserver vorbereiten
Wir aktivieren zuerst das Headers, SSL und Rewrite Modul.
1 2 3 | a2enmod headers a2enmod ssl a2enmod rewrite |
Erstellen eine globale Alias Datei (gültig für alle vHosts).
1 2 3 4 5 6 7 8 | Alias /.well-known /var/www/letsencrypt/.well-known <Directory /var/www/letsencrypt> Require all granted ##Use this for old Apache 2.2 # Order allow,deny # Allow from all </Directory> |
oder für Apache >=2.4
1 2 3 4 5 6 7 8 | Alias /.well-known /var/www/letsencrypt/.well-known <Directory /var/www/letsencrypt> Require all granted ##Use this for old Apache 2.2 # Order allow,deny # Allow from all </Directory> |
Bei der 2. Variante aktivieren wir die Konfiguration noch.
1 | a2enconf letsencrypt.conf |
Jetzt legen wir den Alias-Ordner an und verteilen die korrekten Rechte.
1 2 | mkdir -p /var/www/letsencrypt/.well-known chown www-data. /var/www/letsencrypt -R |
Die CipherSuite wird auf einen aktuellen Stand gebracht (hier gibt es aktuelle Ciphers cipherli.st).
1 2 3 | SSLProtocol All -SSLv2 -SSLv3 SSLHonorCipherOrder On SSLCipherSuite "HIGH+kEECDH+AESGCM:HIGH+kEECDH:HIGH+kEDH:HIGH:!aNULL" |
Apache neustarten.
1 2 3 | service apache2 restart - oder - systemctl restart apache2 |
Punkt 2: Let’s Encrypt: acme.sh
Wir installieren acme.sh. Dies ist ein schlankes Shell Script welches jede Let’s Encrypt Funktion wie issue, renew, cronjob etc. mit sich bringt. Es wird automatisch ein Cronjob angelegt der täglich ein renew für alle Domains anfragt.
1 2 3 4 5 | apt install -y socat curl https://get.acme.sh | sh source .bashrc acme.sh --set-default-ca --server letsencrypt acme.sh --set-default-chain --preferred-chain "ISRG" --server letsencrypt |
Einen Ordner für die Zertifikate legen wir in folgender Datei fest, ich empfehle den bereits vorhandenen Ordner /etc/ssl/private.
1 | CERT_HOME="/etc/ssl/private" |
Wir schließen das Konsolenfenster und verbinden uns zum Server neu, um die Umgebungsvariable von acme.sh zu laden. Das Script ist nun direkt ausführbar.
Punkt 3: Zertifikat erstellen
Beginnen wir mit einem Test, die obigen Einstellungen sollten zuerst immer mit „–test“ geprüft werden. Let’s Encrypt lässt nur 5 Versuche in 7 Tagen zu, danach ist die Domain temporär gesperrt. Ich empfehle in diesem Zuge von 2048-Bit oder 4096-Bit RSA Keys gleich auf das modernere ec-256 (ECDSA P-256) zu wechseln. Zum einen bringt dies eine höhere Sicherheit und zum anderen sind die Keys kürzer und somit performanter.
1 | acme.sh --issue --test -k ec-384 -w /var/www/letsencrypt -d DOMAIN.de -d www.DOMAIN.de --reloadcmd "systemctl reload apache2.service" |
TIPP: Wenn der Alias /var/www/letsencrypt nicht funktioniert, könnt ihr auch den DocumentRoot verwenden.
1 | acme.sh --issue --test -k ec-384 -w /var/www/html/DOMAIN.de -d DOMAIN.de -d www.DOMAIN.de --reloadcmd "systemctl reload apache2.service" |
Sollte die Verifizierung erfolgreich gewesen sein, findet ihr folgende Dateien wieder.
1 2 3 4 5 6 7 8 9 10 11 | localhost:~# ls -lah /etc/ssl/private/DOMAIN.de insgesamt 36K drwxr-xr-x 2 root root 4,0K Jul 12 08:00 . drwxr-xr-x 6 root root 4,0K Jul 12 15:37 .. -rw-r--r-- 1 root root 1,7K Jul 12 08:00 DOMAIN.de.cer -rw-r--r-- 1 root root 528 Jul 12 08:00 DOMAIN.de.conf -rw-r--r-- 1 root root 574 Jul 12 07:59 DOMAIN.de.csr -rw-r--r-- 1 root root 302 Jul 12 07:59 DOMAIN.de.key -rw-r--r-- 1 root root 314 Jul 12 07:59 DOMAIN.de.ssl.conf -rw-r--r-- 1 root root 1,7K Jul 12 08:00 ca.cer -rw-r--r-- 1 root root 3,3K Jul 12 08:00 fullchain.cer |
Diesen Ordner können wir löschen, da mit „–test“ die Staging API von Let’s Encrypt genutzt wird und nur Fake Zertifikate ausgestellt werden.
1 | rm -r /etc/ssl/private/DOMAIN.de |
Das echte Zertifikat kann nun ausgestellt werden. (--force
um das Testzertifikat zu überschreiben)
1 2 3 | acme.sh --issue -k ec-384 -w /var/www/letsencrypt -d DOMAIN.de -d www.DOMAIN.de --reloadcmd "systemctl reload apache2.service" --force - oder - acme.sh --issue -k ec-384 -w /var/www/html/DOMAIN.de -d DOMAIN.de -d www.DOMAIN.de --reloadcmd "systemctl reload apache2.service" --force |
Punkt 4: Zertifikat in Apache einbinden
Wir editieren unsere vHost Config und fügen das soeben erstelle Zertifikat sowie Security Headers ein.
Ich möchte an dieser Stelle darauf hinweisen, dass ich Public Key Pinning (HPKP) in dieser Anleitung bewusst außenvor lasse um ein eventuelles Aussperren von Besuchern zu verhindern. Wer sich dieser Gefahr bewusst ist, kann gerne meiner Anleitung folgen.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <VirtualHost *:80> ... RewriteEngine On RewriteCond %{REQUEST_URI} !^/\.well\-known/acme\-challenge/ RewriteCond %{HTTPS} off RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L] ... </VirtualHost> <VirtualHost *:443> ... # SSL Zertifikat SSLEngine on SSLCertificateFile /etc/ssl/private/DOMAIN.de/fullchain.cer SSLCertificateKeyFile /etc/ssl/private/DOMAIN.de/DOMAIN.de.key SSLCertificateChainFile /etc/ssl/private/DOMAIN.de/ca.cer # Hardening Apache2 Headers Header always set Content-Security-Policy "default-src https: data: 'unsafe-inline' 'unsafe-eval'" Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" Header always set X-Frame-Options "SAMEORIGIN" Header always set X-Xss-Protection "1; mode=block" Header always set X-Content-Type-Options nosniff ... </VirtualHost> |
Apache neustarten.
1 2 3 | service apache2 restart - oder - systemctl restart apache2 |
Das Ergebnis prüfen wir auf SSL Labs und Security Headers.
Punkt 1: Nginx Webserver vorbereiten
Wir erstellen die nötigen Ordner und eine globale Datei die in jeden vHost „included“ wird. Das vereinfacht späteres Anpassen.
1 2 3 | mkdir /etc/nginx/global mkdir -p /var/www/letsencrypt chown www-data. /var/www/letsencrypt -R |
1 2 3 4 5 6 7 8 9 | location /.well-known/acme-challenge { root /var/www/letsencrypt; default_type "text/plain"; try_files $uri =404; } location / { return 301 https://$host$request_uri; } |
Für die globalen SSL Einstellungen legen wir ebenfalls eine Datei an. Die Ciphers werden auf einen aktuellen Stand gebracht (hier gibt es aktuelle Ciphers cipherli.st). Auch die Security Headers werden hier hinterlegt.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | ssl_dhparam /etc/nginx/dhparams.pem; ssl_buffer_size 1400; ssl_session_timeout 1d; ssl_session_cache shared:SSL:50m; ssl_session_tickets off; ssl_protocols TLSv1.2 TLSv1.3; ssl_early_data on; ssl_ciphers EECDH+CHACHA20:EECDH+AESGCM:EDH+CHACHA20:EDH+AESGCM:!DSS; ssl_prefer_server_ciphers on; ssl_stapling on; ssl_stapling_verify on; ssl_ecdh_curve X25519:P-384:P-256:P-521; resolver_timeout 5s; add_header Content-Security-Policy "default-src https: data: 'unsafe-inline' 'unsafe-eval'" always; add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload"; add_header X-Xss-Protection "1; mode=block" always; add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "SAMEORIGIN" always; |
Falls noch nicht vorhanden, legen wir eine dhparams Datei an.
1 | openssl dhparam -out /etc/nginx/dhparams.pem 4096 |
Nginx neustarten.
1 2 3 | service nginx restart - oder - systemctl restart nginx |
Punkt 2: Let’s Encrypt: acme.sh
Wir installieren acme.sh. Dies ist ein schlankes Shell Script welches jede Let’s Encrypt Funktion wie issue, renew, cronjob etc. mit sich bringt. Es wird automatisch ein Cronjob angelegt der täglich ein renew für alle Domains anfragt.
1 2 3 4 5 | apt install -y socat curl https://get.acme.sh | sh source .bashrc acme.sh --set-default-ca --server letsencrypt acme.sh --set-default-chain --preferred-chain "ISRG" --server letsencrypt |
Einen Ordner für die Zertifikate legen wir in folgender Datei fest, ich empfehle den bereits vorhandenen Ordner /etc/ssl/private.
1 | CERT_HOME="/etc/ssl/private" |
Wir schließen das Konsolenfenster und verbinden uns zum Server neu, um die Umgebungsvariable von acme.sh zu laden. Das Script ist nun direkt ausführbar.
Punkt 3: Zertifikat erstellen
Beginnen wir mit einem Test, die obigen Einstellungen sollten zuerst immer mit „–test“ geprüft werden. Let’s Encrypt lässt nur 5 Versuche in 7 Tagen zu, danach ist die Domain temporär gesperrt. Ich empfehle in diesem Zuge von 2048-Bit oder 4096-Bit RSA Keys gleich auf das modernere ec-256 (ECDSA P-256) zu wechseln. Zum einen bringt dies eine höhere Sicherheit und zum anderen sind die Keys kürzer und somit performanter.
1 | acme.sh --issue --test -k ec-384 -w /var/www/letsencrypt -d DOMAIN.de -d www.DOMAIN.de --reloadcmd "systemctl reload nginx.service" |
TIPP: Wenn die Location /var/www/letsencrypt nicht funktioniert, könnt ihr auch den Root verwenden.
1 | acme.sh --issue --test -k ec-384 -w /var/www/html/DOMAIN.de -d DOMAIN.de -d www.DOMAIN.de --reloadcmd "systemctl reload nginx.service" |
Sollte die Verifizierung erfolgreich gewesen sein, findet ihr folgende Dateien wieder.
1 2 3 4 5 6 7 8 9 10 11 | localhost:~# ls -lah /etc/ssl/private/DOMAIN.de insgesamt 36K drwxr-xr-x 2 root root 4,0K Jul 12 08:00 . drwxr-xr-x 6 root root 4,0K Jul 12 15:37 .. -rw-r--r-- 1 root root 1,7K Jul 12 08:00 DOMAIN.de.cer -rw-r--r-- 1 root root 528 Jul 12 08:00 DOMAIN.de.conf -rw-r--r-- 1 root root 574 Jul 12 07:59 DOMAIN.de.csr -rw-r--r-- 1 root root 302 Jul 12 07:59 DOMAIN.de.key -rw-r--r-- 1 root root 314 Jul 12 07:59 DOMAIN.de.ssl.conf -rw-r--r-- 1 root root 1,7K Jul 12 08:00 ca.cer -rw-r--r-- 1 root root 3,3K Jul 12 08:00 fullchain.cer |
Diesen Ordner können wir löschen, da mit „–test“ die Staging API von Let’s Encrypt genutzt wird und nur Fake Zertifikate ausgestellt werden.
1 | rm -r /etc/ssl/private/DOMAIN.de |
Das echte Zertifikat kann nun ausgestellt werden. (--force
um das Testzertifikat zu überschreiben)
1 2 3 | acme.sh --issue -k ec-384 -w /var/www/letsencrypt -d DOMAIN.de -d www.DOMAIN.de --reloadcmd "systemctl reload nginx.service" --force - oder - acme.sh --issue -k ec-384 -w /var/www/html/DOMAIN.de -d DOMAIN.de -d www.DOMAIN.de --reloadcmd "systemctl reload nginx.service" --force |
Punkt 4: Zertifikat in Nginx einbinden
Wir editieren unsere vHost Config und fügen das soeben erstelle Zertifikat sowie Security Headers ein.
Ich möchte an dieser Stelle darauf hinweisen, dass ich Public Key Pinning (HPKP) in dieser Anleitung bewusst außenvor lasse um ein eventuelles Aussperren von Besuchern zu verhindern. Wer sich dieser Gefahr bewusst ist, kann gerne meiner Anleitung folgen.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | server { listen 80; server_name DOMAIN.de www.DOMAIN.de; include /etc/nginx/global/redirect.conf; } ... server { listen 443 ssl http2; server_name DOMAIN.de www.DOMAIN.de; ... ssl_certificate /etc/ssl/private/DOMAIN.de/fullchain.cer; ssl_certificate_key /etc/ssl/private/DOMAIN.de/DOMAIN.de.key; ssl_trusted_certificate /etc/ssl/private/DOMAIN.de/ca.cer; include /etc/nginx/global/ssl.conf; ... |
Nginx neustarten.
1 2 3 | service nginx restart - oder - systemctl restart nginx |
Das Ergebnis prüfen wir auf SSL Labs und Security Headers.
Das Betreiben der Dienste, Webseite und Server machen wir gerne, kostet aber leider auch Geld. Unterstütze unsere Arbeit mit einer Spende. |
Deine Anleitung hat mir echt weitergeholfen!
Als Anfänger ist allerding der Beispielordner „/var/www/letsencrypt“ recht verwirrend, da der Name des Ordners „letsencrypt“ nichts mit Letsencrypt zu tun hat.
Der Ordner könnte auch „/var/www/beispiel“ heißen und zur URL http://www.beispiel.de gehören.
Hoffe meine Bemerkung hilft andern weiter.
guten tag. ich danke dir sehr!
endlich eine anleitung, die ich verstehe 😉
ich habe apache2 (ubuntu 16.04).
es gibt ein paar kleine winzigkleine unlogeleien bezüglich apache2.4
/etc/apache2/conf.d/letsencrypt.conf versus /etc/apache2/conf-available/letsencrypt.conf
ich würde in beispielen nicht das alte UND zeitgleich das neue apache erwähnen. mann sieht es ja an der überschrift, welches der beiden apachen gemeint ist!
was vielleicht fehlen könnte, ist der hinweis, was mache ich denn, wenn ich schon meine tests habe, wie kille ich die. wie errichte ich dann neue certs, wie melde ich die an. wenn man vesteht, daß das in drei von einander ubhängigen schritten ablaufen muss/kann. dann hat man viel versdanden 😉
deshalb bei mir 4 schritte:
1. acme.sh –remove -d…
2. acme.sh –issue -k ec-256 –apache -d…
3. acme.sh –install-cert –ecc -k ec-256 –apache -d…
4. acme.sh –install-cronjob -k ec-256 –apache -d…
ich verwende gerne in meinen skripten platzhalter. z.b. :
export s=“domain.de“
export a=“/etc/apache2″
man verkürzt sich seine skripte damit! und ich erledige in einem aufruf 1xdomain und dafür 4sibdomains.
was auch schön ist, zu erwähnen: ich plaziere die schlüssel gleich mit dem befehl an die stelle, wo sie der übersichthalber „hingehören“.
–cert-file $a/$s.cert.pem –key-file $a/$s.key.pem –ca-file $a/$s.ca.pem –fullchain-file $a/$s.fullchain.pem
vielleicht, wenn DU möchtest, werde ich dir die dateien schicken (meine 4 scripte, sie sind fast selbsterklärend 😉
danke, danke erstmal!
viele grüße, klaus lehmann
Vielen Dank für deine Anregungen. Ich habe ein
--force
hinzugefügt, damit die Testzertifikate einfach überschrieben werden können.Die Anleitung soll nur als Grundlage dienen, jede weitere Konfiguration kann ein Admin gerne selbst durchführen 😉
Deine Skripte sind willkommen, kannst du mir gerne schicken.
Dominion, danke für Deine Antwort! Aber ich muß dem widersprechen: „Die Anleitung soll nur als Grundlage dienen, jede weitere Konfiguration kann ein Admin gerne selbst durchführen“.
Naja.Iich denke schon, daß ich ein solcher „admin“ bin, betreibe ich doch seit 2003 meine 3-7 eigenen Server, alle volle root-server auf linux. aber wenn ich die doku (das wiki) oder die –help zeile zu acme.sh sehe, und VERSUCHE sie zu verstehen. naja.
es ist alles so ziemlich mehrdeutig oder „ohne deutigkeit“ formuliert. wo steht denn z.b. drin, wie ich meine domian und die 4 subdomains um weitere subdomains ergänzen kann? das findet man nicht! ausprobieren? oh ja: GERNE! nur nach 5 versuchen innnerhalb 7 tagen wirst DU rausgekickt!
Die dt. Doku, die DU, lieber Dominion schon 2016 veröffentlichst hast, ist a. sehr gut, und b. sie funktioniert (DAS ist keine selbstverständlichkeit! bei dem Müll, der in blogs und Konsorten geschrieben). und mir wäre es sehr lieb, wenn man hier (gute) fragen stellen kann, und auch andere ihren senf beitragen 😉
Nächster (mein) Beitrag zum Thema: „Wie erweitere ich meine vorhandene Domain um weitere Subdomains“
Grüße, Klaus Lehmann
PS: in der c’t 2018/4 steht was zum neuen acme-protokoll drin, sowie zum neuen mod in apache. Wer !genau! liest, sieht beim Protokoll 2.0 und acme.sh die Einschränkung (Stichwort DNS). und apache’s mod_md ist nicht ausgereift und es ist keine Selbstverständlichkeit, es in ältere apache2 integriert zu bekommen.
allet nich so einfach, nee nich…..
Beitrag zum Thema: „Wie erweitere ich meine vorhandene Domain um weitere Subdomains“
hm. ich machte die erfahrung, das das alles ganz doll und tolle geklappt hatte.
ups, ich hatte 2 subdmänen vergessen.
was habe ich nun gemacht? es steht auch nicht beim originalwiki, wie man „das vorhandene“ um „weitere subdomänen“ ergänzt!
also habe ich es so gemacht, in dem ich schrieb: (logisch tztztz denkend)
mmz und psb sind meine NEUEN domänen! die hauptdomäne ist zzzdomainzzz.de …
/root/.acme.sh/acme.sh –issue -k ec-256 –apache -d http://www.zzzdomainzzz.de -d zzzdomainzzz.de -d mmz.zzzdomainzzz.de -d http://www.mmz.zzzdomainzzz.de -d psb.zzzdomainzzz.de -d http://www.psb.zzzdomainzzz.de –cert-file $a/zzzdomainzzz.de.cert.pem –key-file $a/zzzdomainzzz.de.key.pem –ca-file $a/zzzdomainzzz.de.ca.pem –fullchain-file $a/zzzdomainzzz.de.fullchain.pem –webroot /home/zzzdomainzzz.de/public_html –force –ecc –reloadcmd „service apache2 force-reload“
das hatte zum ergebnis: die vorhandenen alten subdomänen wurden alle gelöscht!
die domäne „zzzdomainzzz.de“ selber nicht!
autsch!
die erfahrung: dat janze nochmal! aufs neue!
1. /root/.acme.sh/acme.sh –issue -k ec-256 –apache -d http://www.zzzdomainzzz.de -d zzzdomainzzz.de mit allen ALTEn und NEUEN subdomänen!
es hat zumindestens geklappt!
wer ein besseres/kürzeres rezept hat, widerspreche mir BITTE liebendgern!
2. immer im hinteren kopfe: fünef versuche pro sieben tager sind erlaubt! mehr iss nicht!
gruezi, vom klaus(i)
Ich muss meinen Server (nginx based) auf einen anderen Provider umziehen und bin mir nicht sicher ob es reicht auf dem neuen Zielsystem einfach nur acme.sh (läuft bei mir unter eigenem User) zu installieren und danach alle Zertifikate zu kopieren. Auch ob danach noch die automatische Aktualisierung über die crontab funktioniert? Eine Idee?
Hallo Matthias,
ja installiere dir auf dem neuen System einfach auch acme.sh. Anschließend kannst du dir die Zertifikate rüber kopieren.
Der Cronjob erkennt automatisch die Zerts im Ordner und macht ein Renew falls nötig.
Gruß
Dominion