Update: Mittlerweile gibt es einen einfacheren Weg ;)

Irgendwie hatte ich es mal geschafft, ein paar Domains für die closed Beta von Let’s Encrypt! zu registrieren, heute kam dann endlich die Mail mit der Bestätigung freu.

Lets Encrypt! ist eine Initiative unter anderem von Mozilla, Cisco, Akamai und der EFF, welche es sich auf die Fahne geschrieben hat, einfach, kostenlos und sichere SSL-Zertifikate anzubieten. Nachdem am 19.10.15 endlich das cross-signing der Root-CAs durch war, werden jetzt die ersten Zertifikate an Betateilnehmer ausgegeben (ick freu mir wie nen karnickel :D). Durch dieses Cross-Signing werden die Let’s Encrypt-Zertifikate von allen Browsern ohne Probleme angenommen. Ein kleines Manko könnte aktuell noch sein, dass man das Zertifikat alle 90 Tage (besser 60) erneuern muss, Let’s Encrypt arbeitet aber schon an einem verbesserten Auto-Updater, sodass man sich nicht mal mehr darum kümmern muss.

Wie bereits erwähnt, soll das Erstellen des Zertifikates sehr einfach sein, also optimal, um meine bei Uberspace gehostete Domain mit dem cert zu versehen.

Erste Schritte

Auch wenn in der Let’s Encrypt-Mail steht, dass die Installation sehr einfach ist, benötigt sie doch auf dem Webserver, auf welchem die Domain liegt, Rootberechtigungen. Das ist allerdings auf Shared-Hostern nicht gegeben -> man kann nicht die Offizielle Software verwenden. Doch auch hier findet sich schnell eine Lösung in form eines kleinen Scriptes: github.com/diafygi/letsencrypt-nosudo.

Dieses ermöglicht es, die Zertifikats-Validierung ohne Root-Rechte durchzuführen (nach einer kleinen Modifikation):

Auf dem Uberspace muss im Webroot ein neues Verzeichnis erstellt werden:

mkdir .well-known

In diesem Verzeichnis muss nun eine .htaccess-Datei mit folgendem Inhalt angelegt werden:

RewriteEngine on
RewriteRule . letsEncrypt.php

Diese leitet alle Anfragen, welche unterhalb des .well-known-Ordners ankommen auf die letsEncrypt.php, welche den folgenden Inhalt hat:

letsEncrypt.php

<php
header('Content-Type: application/jose+json');

echo "";

Jetzt ist alles vorbereitet und man kann nach einem

git clone https://github.com/diafygi/letsencrypt-nosudo.git

den Schritten auf der Seite folgen um das Zertifikat zu generieren.

Generieren des Zertifikates

Wenn das Script einen dazu auffordert einen Python-Code als sudo auszuführen:

[...] You need to run this command on igorshp.de (don't stop the python command until the next step).

sudo python -c "import BaseHTTPServer; \
h = BaseHTTPServer.BaseHTTPRequestHandler; \
h.do_GET = lambda r: r.send_response(200) or r.end_headers() or r.wfile.write('{\"header\": {\"alg\": \"RS256\"}, \"protected\": \"[...]\", \"payload\": \"[...]\"}'); \
s = BaseHTTPServer.HTTPServer(('0.0.0.0', 80), h); \
s.serve_forever()"

Hier muss man sich den Inhalt, beginnend mit der geschweiften öffnenden Klammer ({) und endend mit der geschweiften schließenden Klammer (}) kopieren und zwischen die doppelten Anführungszeichen des Echos im Script eingeben & im Terminal mit Enter bestätigen, sodass dieses etwa so aussieht:

letsEncrypt.php

<?php
header('Content-Type: application/jose+json');

echo "{\"header\": {\"alg\": \"RS256\"}, \"protected\": \"[...]\", \"payload\": \"[...]\"}";

Dadurch werden alle Anfragen nach dem schema http://[domain.tld]/.well-known/acme-challenge/[langerhashwert] mit dem angegebenen String beantwortet und damit die Domain verifiziert.

Diesen schritt muss man noch ein zweites mal wiederholen und schon hat man sein eigenes Zertifikat!

Einrichten bei Uberspace

Als letzten Schritt muss noch der .well-known-Ordner vom Server gelöscht werden und das Zertifikat auf den Uberspace gespeichert werden. Also schnell die signed.crt und die domain.key per SSH/SFTP auf den Uberspace-Host hochladen (diese muss direkt im Home oder in einem angelegten Unterordner liegen, !NICHT! im webroot!) und mit ein paar Befehlen das einbinden vorbereiten (es wird eine user.domain.combined.pem-Datei erstellt):

wget https://letsencrypt.org/certs/lets-encrypt-x1-cross-signed.pem
uberspace-prepare-certificate -i lets-encrypt-x1-cross-signed.pem -k domain.key -c signed.crt

Wenn alles geklappt hat, muss nur noch eine Mail an hallo@uberspace geschrieben werden & das Zertifikat kann verwendet werden :)

Kommentare

– JoJota, 4.11.15 22:41

Hallo Igor, danke für den interessanten Artikel! Ich bekomme bei der Installation auf meinem Uberspace leider mit dem Befehl „python sign_csr.py –public-key user.pub domain.csr > signed.crt“ nur die folgende Fehlermeldung:

Traceback (most recent call last):

File "sign_csr.py", line 426, in
signed_crt = sign_csr(args.public_key, args.csr_path, email=args.email)
File "sign_csr.py", line 18, in sign_csr
nonce_req = urllib2.Request("{}/directory".format(CA))
ValueError: zero length field name in format

Irgendeine Idee woran das liegen kann?

Gruß JoJota

– Igor, 4.11.15 22:56

Hallo JoJota!

Das liegt an der verwendeten Python Version. Dieses ist bei Uberspace standard die 2.6, benötigt wird aber mind. 2.7: Auf deinem Uberspace-host muss du also anstatt python sign_csr.py [...] folgenden Command benutzen: python2.7 sign_csr.py [...]

– JoJota, 5.11.15 12:30

Hat funktioniert. Vielen Dank!

– GALORE, 11.11.2015 0:26

Hallo Igor! Vielen Dank für die Anleitung! Nur leider habe ich Probleme bei „Generieren des Zertifikates“. Wenn das Script einen dazu auffordert einen Python-Code als sudo auszuführen. Wenn ich den String von von { bis } in die „“ vom echo in die letsEncrypt.php eingefügt habe und dann im Terminal mit Enter bestätige bekomme ich folgende Fehlermeldung:

Traceback (most recent call last): File „sign_csr.py“, line 431, in signed_crt = sign_csr(args.public_key, args.csr_path, email=args.email) File „sign_csr.py“, line 365, in sign_csr raise KeyError(„‚{}‘ challenge did not pass: {}“.format(i[‚domain‘], challenge_status)) KeyError: „‚meinedomain.com‘ challenge did not pass: {u’status‘: u’invalid‘, u’tls‘: False, u’validationRecord‘: /* …. */ u’error‘: {u’type‘: u’urn:acme:error:unauthorized‘, u’detail‘: u’Validation response failed to parse as JWS: square/go-jose: compact JWS format must have three parts‘}, u’type‘: u’simpleHttp‘}“

Um den Fehler einzugrenzen, mit Webroot meinst du /var/www/virtual/$USER/ ? Hier wird das .well-known Verzeichnis mit der .htaccess erstellt /var/www/virtual/$USER/.well-known/.htaccess. Wo muss dann die letsEncrypt.php hin ?

Irgend eine Idee was ich falsch mache ?

– Igor, 13.11.2015 8:19

Mit Webroot ist der /var/www/virtual/$USER/html/-Ordner gemeint (der LetsEncrypt-Server verbindet sich nach meinedomain.com/.well-known/***, in diesen Ordner gehört die .htaccess und die .php-Datei :)

Muss das Zertifikat nicht alle 3 Monate erneuert werden? Wie geht man dann vor?

Ben, 13.11.2015, 9:30

– Igor, 13.11.2015 19:12

Genau, aktuell muss man die Zertifikate leider alle 3 Monate erneuern, dies kann aber auch automatisch erfolgen (cronjob etc.), allerdings ist das in dem Script leider noch nicht implementiert.

Aber: es wird bereits ein Issue auf Github erstellt, es ist also nur noch eine Frage der Zeit :D

https://github.com/diafygi/letsencrypt-nosudo/issues/10

– Jonas, 16.11.2015, 0:51

Hallo Igor, vielen Dank für die ausführliche Anleitung!

Eine kleine Anmerkung dazu, die anderen Ubernauten helfen könnte:

Und zwar habe ich alle Schritte wie beschrieben durchgeführt. Allerdings erhielt ich vom letsencrypt-nosudo Skript kein JSON / Python Webserver Snippet, wie im Beitrag beschrieben, sondern nur einen hash-artigen Text (r.wfile.write(‚FcABC-123xyz(…).r-UU123(…)_X11b‘). Dadurch funktionierte dann der letzte Teil deiner Anleitung mit der letsEncrypt.php Datei leider nicht mehr und ich erhielt die folgende Fehlermeldung:

Error parsing key authorization file / Invalid key authorization: malformed key thumbprint

Nach mehreren Versuchen und etwas googeln habe ich dann die Lösung gefunden und zwar will letsencrypt den korrekten Content-Type haben was in meinem Fall dann „text/plain“ war.

TL;DR Falls ihr kein JSON bekommt einfach „application/jose+json“ durch „text/plain“ ersetzen und den hash-artigen Text anstatt des JSONs einfügen dann sollte alles klappen :)

Gruß, Jonas

– Igor, 28.12.2015, 1:28

Das stimmt, das wurde vereinfacht :D

Jetzt reicht es, in der .htaccess-Datei folgende Zeilen stehen zu haben:

RewriteEngine on
RewriteRule . letsEncrypt.txt

Die 2 Zeichenketten können dann einfach in der letsEncrypt.txt eingetragen werden, wenn das Script einen danach fragt!

(Die Zeile aus der der Code kopier werden muss sieht übrigens so aus:)

[...] r.end_headers() or r.wfile.write('[Diese Zeichenkette muss in die letsEncrypt.txt]'); [...]

– Dominique, 20.11.2015, 0:23

Ich wollte nur schnell sagen: Danke für diesen Artikel! Der hat mich am Ende gerettet.