https mit letsencrypt

Setup von https mit Zertifikat von letsencrypt.org, letskencrypt und nginx

Posted by Holm Spitzer on 30. August 2016
In Verschlüsselung, Nginx,

Vor einiger Zeit habe ich meine Website auf https mit einem Zertifikat von letsencrypt.org umgestellt.

Nun reiche ich das HowTo dazu nach.
Zuerst habe ich letskencrypt installiert. Warum letskencrypt? Weil es nur libressl als Abhängigkeit hat.

Allerdings habe ich festgestellt, dass seit dem Erstellen des Zertifikats und heute die letskencrypt Version in den ports aktualisiert wurde. Das folgende HowTo bezieht sich auf die nun aktuelle Version 0.1.10 und habe ich während der Ausstattung eines weiteren nginx in einem separaten Jail mit einem Zertifikat von letsencrypt.org nieder geschrieben.

Ich habe letskencrypt mit poudriere bauen lassen und es in zwei Jails installiert. Man kann es natürlich auch mit portmaster oder klassisch mit make install installieren. Wie schon erwähnt habe ich letskencrypt in jedem Jail installiert und nicht im Host-System, da ich das Host-System so schlank und damit die Angriffsfläche so klein wie möglich halten möchte. Mir ist wohler dabei.

Los geht’s.

Zuerst ins Jail wechseln, egal ob mit ezjail oder klassisch mit jexec.

letsencrypt.org wird später auf das Verzeichnis /.well-known/acme-challenge zugreifen. Wir wechseln also ins document root Verzeichnis unseres Webservers. Man (ich gehöre dazu) kann das Verzeichnis auch außerhalb des document root Verzeichnisses anlegen und in nginx einen alias konfigurieren.

Nun erstellen wir die benötigte Struktur und schränken die Rechte etwas ein:


mkdir -p .well-known/acme-challenge
chmod -R 750 .well-known/acme-challenge

Die Rechte sehen dann so aus:


drwxr-x---   3 root  www     3 Aug  1 16:33 .well-known

Wenn die Struktur außerhalb des document root Verzeichnisses angelegt wurde, muss noch ein alias im Webserver angelegt werden. Außerdem muss sichergestellt werden, dass die Dateien, die letskencrypt in /.well-known/acme-challenge/ ablegt, mit dem content type text/plain ausgeliefert werden. Für nginx fügt man folgende Zeilen in den server-Block ein:


location ^~ /.well-known/acme-challenge/ {
    default_type "text/plain";
    alias /pfad/zum/verzeichnis/.well-known/acme-challenge/;
}

Nun den Webserver einmal Neustarten oder die Konfiguration neu laden.

Um den Zugriff auf das Verzeichnis zu testen, kann man im Verzeichnis acme-challenge eine Textdatei anlegen und diese dann im Browser abrufen. Wenn man den Inhalt sieht ist alles ok.

Jetzt wechseln wir zu /usr/local/etc und erzeugen folgende Verzeichnisse und setzen ein paar Berechtigungen:


cd /usr/local/etc
mkdir ssl/letsencrypt/holminger.de
mkdir letsencrypt/holminger.de
mkdir letsencrypt/private
chmod 700 letsencrypt/private

Nun erstellen wir den privaten Schlüssel im Verzeichnis letsencrypt/holminger.de (Option -k), teilen letskencrypt mit, dass das ausgestellte Zertifikat, sowie das intermediate Zertifikat in ssl/letsencrypt/holminger.de abgelegt werden soll (Option -c), erstellen den account key im Verzeichnis letsencrypt/private (Option -f) und geben den Pfad zum acme-challenge Verzeichnis an (Option -C), sowie den common name (CN) und den subject alternative name (SAN) als letzte Parameter mit. Die Option -n erzeugt einen account key, -N erzeugt den privaten Schlüssel zum ausgestellten Zertifikat und -v schaltet den verbose output ein.


letskencrypt -vnN \
    -k letsencrypt/holminger.de/privkey.pem \
    -c ssl/letsencrypt/holminger.de \
    -f letsencrypt/private/accountkey.pem \
    -C /pfad/zum/verzeichnis/.well-known/acme-challenge \
    holminger.de www.holminger.de

Anschließend sollten im Verzeichnis ssl/letsencrypt/holminger.de folgende Dateien liegen: cert.pem - das reine Zertifikat für unsere Domain
chain.pem - ein intermediate Zertifikat von letsencrypt
fullchain.pem - das Zertifikat für unsere Domain + dem intermediate Zertifikat von letsencrypt

Nun erzeuge ich noch einen Symlink zum privaten Schlüssel.


cd ssl/letsencrypt/holminger.de
ln -s ../../../letsencrypt/holminger.de/privkey.pem

Die nginx Konfiguration habe ich wie folgt erweitert:


    server {
        # use accf_http/accf_data feature of FreeBSD kernel:
        # for http accept_filter=httpready, for https accept_filter=dataready
        listen       80 default_server accept_filter=httpready;
        server_name  holminger.de www.holminger.de;
        return 301 https://$server_name$request_uri;
    }

    # HTTPS server
    server {
        # use accf_data feature of FreeBSD kernel (use dataready for https server)
        listen       443 ssl accept_filter=dataready;
        server_name  holminger.de www.holminger.de;

        ssl on;
        ssl_certificate      /usr/local/etc/ssl/letsencrypt/holminger.de/fullchain.pem;
        ssl_certificate_key  /usr/local/etc/ssl/letsencrypt/holminger.de/privkey.pem;

        ssl_session_cache    shared:SSL:30m;
        ssl_session_timeout  5m;

        ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
        ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA;
        ssl_prefer_server_ciphers  on;

        charset utf-8;

        index index.html;

        root /pfad/zum/documentroot/holminger.de;

        location ^~ /.well-known/acme-challenge/ {
            default_type "text/plain";
            alias /pfad/zum/verzeichnis/.well-known/acme-challenge/;
        }

    }

Die gezeigte Konfiguration zeigt nur den für https nötigen Teil, die Weiterleitung von http zu https, sowie die Konfiguration für den Alias für /.well-known/acme-challenge/ um die spätere Verlängerung des Zertifikats zu ermöglichen. Eigene Blöcke für die Ausführung von PHP-Scripten usw. müssen noch hinzugefügt werden.

Nun noch den Webserver neu starten und https ist für unsere Website aktiv.

Das Aktivieren von Perfect Forward Secrecy, Public Key Pinning, Strict Transport Security und OCSP stapling erfolgt im nächsten Blogbeitrag.