Lokales SSL-Zertifikat einrichten

Ich habe gerade die erste meiner Webseiten auf HTTPS umgestellt. Da ich meine Webseiten lokal entwickele, macht es Sinn, auch diese lokale Entwicklungsversion auf HTTPS umzustellen, damit eventuelle Probleme frühzeitig auffallen. Hier beschreibe ich kurz mein Vorgehen dazu.

Die Arbeitsumgebung

Ich arbeite unter Windows 10 mittlerweile mit dem WAMP-Stack von Bitnami, der mir mit einer Installation Apache und MySQL mitbringt. Die Entwicklungsversion meiner Webseiten rufe ich unter einer lokalen Domain auf, z.B. ammaletu.loc statt ammaletu.de. Dazu habe ich einfach folgendes in die HOSTS-Datei eingetragen:

127.0.0.1	ammaletu.loc

Windows fragt zu dieser nicht-existenten Top-Level-Domain dann keinen Nameserver, sondern wendet sich direct an die IP 127.0.0.1 alias localhost. Im Apache braucht man dann noch einen Virtual Host, der die Anfrage unter der IP 127.0.0.1 bearbeitet. Dazu habe ich in der vhosts_extra.conf-Datei eingetragen:

<VirtualHost 127.0.0.1:80>
	ServerName ammaletu.loc
	DocumentRoot "D:/[Pfad zur Webseite]"
	<Directory "D:/[Pfad zur Webseite]">
		Options FollowSymLinks
		AllowOverride All
		Require all granted
	</Directory>
</VirtualHost>

Diese Datei wird in meinem Setup aus der http.conf heraus eingebunden und enthält alle meine VirtualHost-Definitionen. Ich habe mir die Datei in einen Ordner gelegt, wo ich meine eigenen Änderungen gut sichern kann, damit beim WAMP-Stack-Update nichts verloren geht.

Zertifikat erstellen Teil 1: Root-CA

Ein lokales Zertifikat kann man sich einfach mit dem Tool OpenSSL selbst erstellen. Da ich auf Anhieb keine Windows-Installation gefunden habe, habe ich das auf einem älteren Ubuntu-Laptop gemacht. Es sollte unter Linux eigentlich nie in Problem sein, dieses Tool zu benutzen, denke ich. Für das genaue Vorgehen (auch für den nächsten Schritt) habe ich diese Anleitung benutzt.

Als erstes erstellt man eine eigene Root-CA (CA = Certificate Authority). Die Root-CA ist quasi die Stelle, welche das konkrete Zertifikat dann herausgibt. Da ich mehrere lokale Webseiten auf SSL umstellen muss, habe ich mir die Root-CA an eine zentrale Stelle gespeichert und sie allgemein gehalten. So kann ich sie dann für die weiteren Webseiten wiederverwenden und spare mir dabei Arbeit.

Folgt dafür der verlinkten Anleitung unter dem Punkt „Create the root.cnf“, mit einer Ergänzung: Standardmäßig ist die generierte CA nur 30 Tage gültig. Das ist natürlich Quatsch, mit dem Parameter „-days 3650″ gilt sie dann 10 Jahre. Zusammen also so:

openssl req -x509 -new -days 3650 -keyout root.key -out root.cer -config root.cnf

Ihr habt nun die drei Dateien „root.cnf“, „root.cer“ und „root.key“. Diese solltet ihr gut aufheben, genau wie das für die Root-CA vergebene Passwort.

An dieser Stelle kann man die neue CA auch gleich im Browser bekannt machen. Versuche, meinen Firefox sie aus dem Windows-Zertifikatsstore laden zu lassen, haben bei mir leider nicht funktioniert. Windows kennt nun meine Root-CA zwar, aber Firefox hat von dort irgendwie nichts übernommen, trotz Änderung in der about:config und Neustarts. Egal, importiert man sie eben einmalig in den Browser. Ruft dazu Extras -> Einstellungen -> Datenschutz & Sicherheit -> Zertifikate -> Zertifikate anzeigen auf. Auf dem Tab „Zertifizierungsstellen“ dann einfach die gerade erstellte Datei „root.cer“ importieren. Die Checkbox für „Dieses Zertifikat kann Webseiten identifizieren“ muss dabei gesetzt sein.

Zertifikat erstellen Teil 2: Das Zertifikat

Die neue Root-CA kann nun Zertifikate für die lokalen Webseiten erstellen. Folgt dabei wieder der verlinkten Anleitung, unter dem Punkt „Create the server.cnf“. Ihr erhaltet dann die Dateien „server.csr“, „server.key“ und „server.cer“. Letzteres ist das eigentliche Zertifikat. Die drei Dateien speichere ich mir in einem „cert“-Ordner zu meiner lokalen Seite, aber natürlich so, dass sie außerhalb des git-Projektes liegen und auch nicht mit auf die produktive Seite ausgeliefert werden.

Wichtig wenn ihr das mehrmals macht: Der zweite Befehl, der das eigentliche Zertifikat erstellt, enthält diesen Teil hier: „-set_serial 123″. Wenn man hier jedes Mal die „123″ als Seriennummer nimmt, akzeptiert Apache diese Zertifkate nicht, da die Seriennummer zum ersten auf diese Weise erstellten Zertifkat gehört. Einfach weglassen geht auch nicht. Ich habe dann als Seriennummer einfach das Datum genommen, also z.B. „-set_serial 201903260054″. Man muss halt dran denken, das zu variieren. Den Fehler bemerkt man sonst erst beim Testen und kann das dann alles noch mal machen.

Apache konfigurieren

Damit die lokale Seite per HTTPS aufgerufen werden kann, brauchen wir einen neuen Virtual Host. HTTPS läuft üblicherweise über Post 443, also ergänzen wir in der vhosts_extra.conf:

<VirtualHost 127.0.0.1:443>
	ServerName ammaletu.loc
	DocumentRoot "D:/[Pfad zur Webseite]"
	SSLEngine On
	SSLCertificateFile "D:/[Pfad zum Zertifikatsordner]/server.cer"
	SSLCertificateKeyFile "D:/[Pfad zum Zertifikatsordner]/server.key"
	<Directory "D:/[Pfad zur Webseite]">
		Options FollowSymLinks
		AllowOverride All
		Require all granted
	</Directory>
</VirtualHost>

So, jetzt noch den Apache neustarten, dann klappt der Aufruf der Seite per HTTPS.

Aufruf üer HTTPS

Nun kann man in der .htaccess-Datei der Seite noch sicherstellen, dass die Seite ausschließlich per HTTPS aufgerufen werden kann:

# force HTTPS
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Ruft man nun „http://ammaletu.loc“ auf, so wird man zu „https://ammaletu.loc“ umgeleitet.

Im Apache-Errorlog fand sich übrigens beharrlich diese Warnung:

AH01909: localhost:443:0 server certificate does NOT include an ID which matches the server name

Normalerweise weist einen das daraufhin, dass man z.B. das Zertifikat auf „www.example.org“ ausgestellt, aber im VirtualHost als ServerName „example.org“ eingetragen hat, mit dem Alias „www.example.org“. Das funktioniert dann trotzdem alles, und die Meldung geht weg, wenn man ServerName und ServerAlias vertauscht. In meinem Fall gab es aber keinen Alias, an beiden Stellen stand „ammaletu.loc“.

Nach sehr viel Suchen und Probieren habe ich herausgefunden, dass Bitnami einen Default-Virtual-Host definiert, der hier irgendwie stört. Da ich diesen Default-VirtualHost nicht brauche, habe ich ihn einfach aus der Konfigurationsdatei entfernt. Die betreffende Datei wird von der httpd.conf aus eingebunden und liegt hier: wampstack-7.2.13-1\apache2\conf\bitnami\bitnami.conf. Darin findet sich dieser längere Block:

<VirtualHost _default_:443>
  DocumentRoot "D:/[Pfad zum WAMP-Stack]/apache2/htdocs"
  SSLEngine on
  SSLCertificateFile "D:/[Pfad zum WAMP-Stack]/apache2/conf/server.crt"
  SSLCertificateKeyFile "D:/[Pfad zum WAMP-Stack]/apache2/conf/server.key"
  
  # ...
  
  # Bitnami applications installed with a prefix URL (default)
  Include "D:/[Pfad zum WAMP-Stack]/apache2/conf/bitnami/bitnami-apps-prefix.conf"
</VirtualHost>

Mag sein, dass das für einige Teile des WAMP-Stacks nötig ist. Da ich nur Apache, MySQL und phpMyAdmin davon nutze, kann ich darauf verzichten. Nach einem erneuten Neustart des Apache war die nervige Warnung dann aus dem Log verschwunden.

10 Gedanken zu „Lokales SSL-Zertifikat einrichten

  1. Ich bin nach den Anleitungen vorgegangen, bei mir funktionieren die Zertifikate nicht. Sorry mich macht das wütend 3 Stunden an dem Müll zu sitzen und keinen Erfolg zu haben.
    In meinen Zertifikat steht:
    Die Integrität dieses Zertifikats kann nicht garantiert werden. das Zertifikat ist eventuell beschädigt oder wurde geändert.
    Ist mit Root CA die root.cnf gemeint?

  2. Kann ich verstehen, sowas ist frustrierend. Ohne genauere Infos kann ich hier aber auch nur raten. Wenn ich nach der Fehlermeldung google, dann kommen u.a. Hinweis darauf, dass eine zu geringe Schlüssellänge benutzt wurde. In den cnf-Dateien steht die unter „default_bits“. Sie muss wohl über 1024 liegen, in der Anleitung war 2048 eingetragen.

    Möglich wäre natürlich auch, dass die generierten Dateien tatsächlich verändert wurden, z.B. die Zeilenumbruch-Zeichen, falls sie per SFTP übertragen wurden von einem Client, der sowas automatisch macht. Die müssen alle exakt so bleiben, wie sie angelegt wurden.

    Ansonsten: Wurde die Root-CA korrekt im Browser bekannt gemacht? Welcher Browser ist es überhaupt? Wurde er nach dem Eintrag neugestartet?

    Die CNF-Dateien sind die Konfigurationen, aus denen dann der Kommandozeilen-Aufruf das Zertifikat (die CER-Datei) und einen Private Key (die KEY-Datei) generiert. Das gehört alles zusammen und sollte aufgehoben werden, falls man die Zertifikate mal neu ausstellen möchte.

  3. Problem gelöst. xD jetzt funzt es…
    Meine 2 Fehler waren:
    1.) Die root.cer hatte ich nicht als Vertrauenswürdige Zertifizierungsstelle in Windows eingefügt.
    2.) Ein Fehler in der server.cnf aufgrund der Anleitung. Wenn man da mehrere DNS (DNS.1 = http://www.beispiel.server, DNS.2 = usw.) einträgt dann darf bei commonName = nur * stehen und nicht http://www.beispiel.server sonst ist das Zertifikat fehlerhaft.

    Herausgefunden habe ich es dadurch:
    https://secure.comodo.net/utilities/decodeCSR.html

    Dort kann man per C&P den Code der server.csr einfügen und auch das wildcart Format prüfen.

    Mit dem Befehl kann man die root.cer prüfen
    openssl x509 -in root.cer -text -noout
    In der Mitte der Textausgabe muss CA:TRUE erscheinen, dann ist die root.cer OK.

    Wer unter Windows mit OpenSSL arbeitet kann die Zertifikate auch auf einer anderen Partition erstellen und anschließend auf C:\…..\Apache\ server.crt unsw. einfügen. Dazu Eingabeaufforderung als Admin:

    D:
    cd D:\Pfad\Zu\Den\Zertifikaten
    „C:\Pfad\Zu\OpenSSL-Win64\openssl.exe“ req -x509 -days 365 -new -keyout root.key -out root.cer -config root.cnf

    Was den letzten Befehl betrifft:
    openssl x509 -days 3650 -req -in server.csr -CA root.cer -CAkey root.key -set_serial 123 -out server.cer -extfile server.cnf -extensions x509_ext

    habe ich ihn so verändert:

    openssl x509 -days 3650 -req -in server.csr -CA root.cer -CAkey root.key -set_serial 123 -out server.crt -extfile server.cnf -extensions x509_ext

    Damit ein server.crt anstatt eines server.cer erstellt wird, da mein xampp Apache mit einer server.crt arbeitet.

    Wenn man in der Eingabeaufforderung als Admin:
    mmc
    eingibt kann man in der Konsole die öffnet über snap in in den Zertifakt Ordner von Windows und dort veraltete Zertifikate Problemlos löschen.

    Ansonsten danke für deine Arbeit hat mir sehr geholfen da mein Opera Browser das veraltete Standart Zertifikat mit festen commonName was man mit dem Befehl makecert im Apache erstellen kann nicht akzeptiert. Er will ein Wildcart Zertifikat um eine separate Überprüfung der Server Adresse (DNS) vornehmen zu können. Das Standart Zertifikat hat nur im Internet Explodierer funktioniert.
    Außerdem sind selbst erstellte Zertifikate auch besser wenn es um die länge der Gültigkeit geht.

  4. Vielen Dank für den ausführlichen Kommentar! Das hilft hoffentlich dem ein oder anderen weiter, der ähnliche Probleme hat. Das mit dem Hinzufügen als vertrauenswürdiges Zertifikat in Windows ist spannend. Das habe ich vermutlich gemacht, weil ich anfangs dachte, dass der Browser es komplett von Windows beziehen kann. Das hatte nicht geklappt, war dann aber als Arbeitsschritt vielleicht trotzdem nötig.

  5. Hallo Johannes,

    erstmal Danke für deine ausführliche Anleitung. Leider klappt es bei mir noch nicht so wie gewünscht. Ich konnte das Zertifikat auf dem Server einrichten, sodass ich unter https://localhost auf mein Projekt zugreifen kann. Zunächst habe ich eine Warnung bekommen:

    „Warning: Potential Security Risk Ahead“
    Error code: SEC_ERROR_UNKNOWN_ISSUER

    Hier konnte ich das Risiko akzeptieren und auf https://localhost zugreifen.

    Jetzt möchte ich mit einem anderen Computer im Netzwerk auf den Server zugreifen und bekomme die Fehlermeldung:

    Fehlercode: SSL_ERROR_RX_RECORD_TOO_LONG

    Vielleicht kannst du mir Helfen.

    Liebe Grüße,
    Tim

  6. Hallo Tim,

    falls Du tatsächlich einfach auf einem anderen Rechner „https://localhost“ aufgerufen hast, ist das auch schon die Ursache, denke ich. Dass „localhost“ zu „127.0.0.1″ auflöst, ist bestimmt an einigen Stellen hartcodiert. Dieser andere Rechner hat aber kein Zertifikat unter Port 443 eingerichtet, und das verursacht dann wohl diesen Fehler, soweit ich das gerade ergoogelt habe.

    Der Beitrag drehte sich um das Einrichten eines Zertifikats auf dem lokalen Rechner, für die Entwicklung und zum Testen. Wenn Du also „Server“ schreibst, meinst Du dann eine Maschine, die aus dem Netz erreichbar ist? Dafür wäre „localhost“ kein guter Name. Generell solltest Du am besten eine echte Domain mit einem Zertifikat versehen, auch wenn es eine ausgedachte Adresse ist. „local.host“ meinetwegen. Dann natürlich Apache oder NGINX so einrichten, dass sie auf diese Adresse hören, und das Zertifikat ebenfalls entsprechend einrichten.

    Jeder andere Rechner muss dann natürlich trotzdem wissen, welche IP-Adresse hinter „local.host“ steckt. Du müsstest also von jedem Rechner aus, der auf die Seite zugreifen soll, die Verbindung von IP-Adresse und Domain in der HOSTS-Datei eintragen. Das kann man für einige Maschinen im lokalen Netz sicher machen, aber für eine öffentliche Seite bräuchtest Du eine echte Domain.

    Viele Grüße,
    Johannes

  7. Hallo Johannes,

    danke für deinen Hinweis. Hier noch ein paar Worte, um deine Fragen zu beantworten.
    Ich habe eine VirtualBox mit Ubuntu und Apache2. Hier habe ich den „Server“ eingerichtet und kann dort unter https://localhost auf meine Website zugreifen. Der „Server“ ist nicht aus dem Netz ereichbar, sondern nur im lokalen Netzwerk zum testen. Jetzt möchte ich mit anderen Computern auf die VirtualBox zugreifen.
    Bevor ich das Zertifikat eingerichtet habe, konnte ich unter 192.168.191.102 (IP von der VirtualBox) auf die VirtualBox von anderen Computern zugreifen.
    Nun würde ich gerne unter https://192.168.191.102 auf die VirtualBox zugreifen.

    Ich werde probieren, deine Hinweise umzusetzten.

    Liebe Grüße und frohe Weihnachten,
    Tim

  8. Ein Zertifikat, das Du für „localhost“ ausgestellt hast, ist nicht automatisch auch für die zugehörige IP-Adresse gültig. Wenn Du also im Browser die IP-Adresse mit HTTPS eingibst und der Server schickt dann ein Zertifikat für „localhost“ mit, ist es eigentlich klar, dass das Fehler produziert. Ob man die dann mit einer Ausnahmeregel ignorieren kann, weiß ich so auf Anhieb nicht.

  9. Hallo man kann es sich mittlerweile mit dem Tool mkcert einfacher machen.
    Ist auf github (FiloSottile/mkcert) und gibt für die drei verbreiteten OS.

    mkcert kann man auf der Kommandozeile mit zwei Befehlen ausführen, dann erstellt das Programm ein Schlüsselpaar und instlaliert gleich die CA in Windows (Firefox leider nicht unter Windows, aber man kann einfach in der about:config security.enterprise_roots.enabled auf true setzen, dann meckert der nicht).

    mkcert -install
    mkcert localhost

    Die beiden erstellten Schlüssel (localhost.pem und localhost-key.pem) muss man dann natürlich noch in den Apache einbinden.

  10. Vielen Dank für den Hinweis! Wenn ich mein System mal neu aufsetzen muss, werde ich das ausprobieren.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Bitte beachte die Kommentarregeln: 1) Kein Spam, und bitte höflich bleiben. 2) Ins Namensfeld gehört ein Name. Gerne ein Pseudonym, aber bitte keine Keywords. 3) Keine kommerziellen Links, außer es hat Bezug zum Beitrag. mehr Details...

So, noch mal kurz drüber schauen und dann nichts wie ab damit. Vielen Dank fürs Kommentieren! :-)