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.
Unterstütze unsere Arbeit mit einer Spende. |