letsencrypt

letsencrypt1 ist ein kostenloser Service für SSL-Zertifikate. Die Zertifikate sind 90 Tage gültig und müssen daher regelmäßig aktualisiert werden, z.B. durch einen systemd timer/service.

letsencrypt SSL Zertifikat automatisch erneuern

Es wird ein systemd Service und systemd Timer benötigt. Der Timer soll zweimal2 täglich den Service starten und prüfen ob das Zertifikat erneuert werden muss. Mit dem Programm certbot3 kann man bei letsencrypt Zertifikate anlegen, verändern oder erneuern. Damit certbot gegenüber letsencrypt nachweisen kann das es Zugriff auf die Domain hat, für die ein Zertifikat ausgestellt werden soll, braucht man entweder Zugriff auf die Ports oder Zugriff auf das Verzeichnis /.well-known auf dem Webserver. Um Zugriff auf die Webserver Ports (80, 443) zu bekommen müsste man diesen anhalten, was etwas unpraktisch ist. Alternativ kann man auch das Webroot Verzeichnis für die jeweilige Domain übergeben.

Update mittels anhalten des Webservers

Mittels pre-hook wird der apache (und in meinem Fall auch der openvpn) Dienst gestoppt. Damit certbot Zugriff auf die Ports zum authentifizieren bekommt. Nach dem Update der Zertifikate werden die Dienste durch den post-hook wieder gestartet. Der pre- und post-hook werden nur ausgeführt, wenn das Zertifikat erneuert werden muss!

#!/bin/bash
certbot renew --pre-hook "systemctl stop httpd openvpn@server.service" --post-hook "systemctl start httpd openvpn@server.service"

Update bei laufendem Webserver

Leider unterstützt certbot renew aktuell nicht die Angabe mehrerer webroots (In apache2 entspricht das den vhosts), daher muss man certbot certonly nutzen.

#!/bin/bash
certbot --non-interactive certonly --keep-until-expiring --webroot -w /srv/http/root/ -d example.de,ftp.example.de -w /srv/http/blog/ -d blog.example.de

 Systemd Service und Timer anlegen

[Unit]
Description=LetsEncrypt Update Service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/letsencrypt_renew
[Unit]
Description=LetsEncrypt Update Timer

[Timer]
OnCalendar=04,16:22
Persistent=true

[Install]
WantedBy=basic.target

Nun noch den systemd Timer beim booten automatisch aktivieren und starten.

sudo systemctl enable letsencrypt.timer
sudo systemctl start letsencrypt.timer

 

Zertifikat bei letsencrypt registrieren

sudo certbot certonly -a standalone --pre-hook "systemctl stop httpd openvpn@server.service" --post-hook "systemctl start httpd openvpn@server.service" -d example.de,ftp.example.de

oder über einen laufenden Webserver

certbot certonly --webroot -w /srv/http/root/ -d example.de,ftp.example.de

 

Weitere SubDomain zum Zertifikat hinzufügen

Ist der gleiche Befehl wie zum registrieren, nur um weitere SubDomains ergänzt.

sudo certbot certonly -a standalone --pre-hook "systemctl stop httpd openvpn@server.service" --post-hook "systemctl start httpd openvpn@server.service" -d example.de,ftp.example.de,blog.example.de

oder über einen laufenden Webserver

certbot certonly --webroot -w /srv/http/root/ -d example.de,ftp.example.de -w /srv/http/blog/ -d blog.example.de

 

Das letsencrypt Zertifikat für den Quassel-IRC Server nutzen

Die eben erstellten Zertfikate liegen unter /etc/letsencrypt/live/example.de/ und können auch für die Verschlüsselung der Kommunikation von Quassel4 Server und Quassel Client genutzt werden. Quassel braucht allerdings ein PEM Bundle aus dem privkey.pem und fullchain.pem und das in /var/lib/quassel/ abgelegt werden muss. Zum Beispiel so:

cat /etc/letsencrypt/live/example.de/privkey.pem /etc/letsencrypt/live/example.de/fullchain.pem > /var/lib/quassel/quasselCert.pem

Das ganze kann man dann mittels post-hook so ausführen.

certbot --non-interactive certonly --keep-until-expiring --webroot -w /srv/http/root/ -d example.de --post-hook "cat /etc/letsencrypt/live/example.de/privkey.pem /etc/letsencrypt/live/example.de/fullchain.pem > /var/lib/quassel/quasselCert.pem && systemctl restart quassel"

 

Django und certbot webroot über apache2

Damit certbot Zugriff auf das /.well-known Verzeichnis in einer Django5 Anwendung hinter dem apache2 bekommt hab ich das /.well-known Verzeichnis nochmal explizit in die apache2 Konfiguration geschrieben. Mit alias wird das Verzeichnis nicht durch django geleitet, sondern direkt von apache2 verarbeitet.

WSGIPythonPath /srv/http/django
<VirtualHost *:443>
    ServerAdmin webmaster@example.de
    DocumentRoot "/srv/http/django/django"
    ServerName django.example.de
    ErrorLog "/var/log/httpd/django.example.de_error_ssl.log"
    CustomLog "/var/log/httpd/django.example.de_access_ssl.log" common

    SSLEngine On
    SSLProtocol All -SSLv2 -SSLv3
    SSLCertificateFile    /etc/letsencrypt/live/django.example.de/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/django.example.de/privkey.pem

    WSGIScriptAlias / /srv/http/django/django/wsgi.py

    # Authentication directory for letsencrypt certificate
    Alias /.well-known /srv/http/django/.well-known
    <Directory "/srv/http/django/.well-known">
        Options -Indexes
        Require all granted
    </Directory>

    Alias /static/ /srv/http/django/static/
    <Location "/static/">
        Options -Indexes
        Require all granted
    </Location>

    <Directory /srv/http/django/django>
        <Files wsgi.py>
            Require all granted
        </Files>
    </Directory>
</VirtualHost>

Fußnoten (Weiterführende Links)

  1. letsencrypt.org
  2. Offizielle Empfehlung ist zweimal täglich:

    if you’re setting up a cron or systemd job, we recommend running it twice per day (it won’t do anything until your certificates are due for renewal or revoked, but running it regularly would give your site a chance of staying online in case a Let’s Encrypt-initiated revocation happened for some reason). Please select a random minute within the hour for your renewal tasks.

    certbot.eff.org/all-instructions/

  3. letsencrypt client: certbot.eff.org
  4. quassel-irc.org
  5. www.djangoproject.com