Selbstsignierte Zertifikate auf Ubuntu richtig erstellen
Erstellen Sie unter Ubuntu 24.04 ein TLS-Zertifikat mit SAN per openssl, binden Sie es in nginx oder Apache ein und schaffen Sie Vertrauen ohne curl -k.
Was Sie erstellen
Ein selbstsigniertes TLS-Zertifikat, das moderne Browser und Clients tatsächlich akzeptieren, mit korrektem subjectAltName, angemessenen Dateiberechtigungen und eingebunden in nginx oder Apache. Dazu kommt der Teil, den fast jede Anleitung auslässt: Ihre Clients sollen dem Zertifikat ordnungsgemäß vertrauen, statt Warnungen wegzuklicken und curl -k dauerhaft fest in Skripte einzubauen. Zum Schluss folgt eine private CA mit fünf Befehlen für den Fall, dass aus einem internen Dienst sechs werden.
Zuerst die Entscheidung: Ein selbstsigniertes Zertifikat ist deutlich seltener das richtige Werkzeug, als es eingesetzt wird. Wenn der Dienst unter einem echten DNS-Namen aus dem öffentlichen Internet erreichbar ist, lesen Sie nicht weiter. Richten Sie stattdessen ein kostenloses Let's-Encrypt-Zertifikat mit certbot unter nginx oder die entsprechende Lösung für Apache ein. Das kostet nichts, erneuert sich automatisch, und gängige Browser und Betriebssysteme vertrauen der Zertifizierungsstelle bereits. Ein selbstsigniertes Zertifikat auf einer öffentlich erreichbaren Website gewöhnt Ihre Benutzer daran, Sicherheitswarnungen zu ignorieren. Das ist eine schlechtere Gewohnheit als reines HTTP.
Selbstsignierte Zertifikate sind das richtige Werkzeug, wenn das öffentliche Internet keine Rolle spielt: für ein Administrationspanel, das an eine WireGuard-Tunneladresse auf Ihrem VPS gebunden ist, einen Staging-Server in einem privaten Netzwerk, Datenverkehr zwischen Backend-Diensten, ein Gerät im Homelab oder zum Ersetzen des Platzhalterzertifikats, das Webmin für sich selbst auf Port 10000 erzeugt. Let's Encrypt kann für 10.8.0.1 oder git.internal.lan ohnehin keine Zertifikate ausstellen. Keine öffentliche CA nimmt eine private IP-Adresse oder eine erfundene TLD in ein Zertifikat auf. Für diese Namen sind Sie die CA.
Alles Folgende läuft auf einem frisch installierten Ubuntu 24.04 mit OpenSSL 3.0.x (openssl version zur Bestätigung). Dafür ist kein Internetzugriff erforderlich. Die Schritte funktionieren vollständig in einer vom Netzwerk getrennten Umgebung.
Warum der alte Einzeiler Zertifikate erzeugt, die Chrome ablehnt
Der Befehl, den jedes Tutorial aus der Zeit vor 2017 vorgibt, sieht so aus:
# Do not run this: shown so you recognise it in old guides
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout selfsigned.key -out selfsigned.crtEr stellt eine Reihe interaktiver Fragen, trägt Ihren Hostnamen in das Feld Common Name ein und erzeugt ein Zertifikat ohne subjectAltName-Erweiterung. Dieses Zertifikat ist von Anfang an unbrauchbar. Chrome ignoriert den Common Name seit Version 58 aus dem April 2017. RFC 2818 hatte die Abgleichung über CN bereits im Jahr 2000 als veraltet eingestuft. Firefox und Safari verhalten sich genauso. curl und das Python-Modul ssl verwenden weiterhin den Common Name als Fallback, wenn ein Zertifikat überhaupt keinen SAN enthält. Deshalb kann ein Zertifikat ohne SAN einen schnellen curl-Test bestehen und trotzdem in jedem Browser fehlschlagen. Für einen Browser identifiziert ein Zertifikat seinen Server über die SAN-Erweiterung oder gar nicht. Der Browser weist Sie mit genau diesen Worten darauf hin:
NET::ERR_CERT_COMMON_NAME_INVALID
This server could not prove that it is git.internal.lan; its security
certificate does not specify Subject Alternative Names.Keine Änderung am Truststore behebt diesen Fehler, weil das Zertifikat tatsächlich keinen Namen enthält. Wenn Sie gerade NET::ERR_CERT_COMMON_NAME_INVALID sehen, enthält Ihr Zertifikat keinen SAN oder den falschen SAN. Sie müssen ein neues Zertifikat ausstellen. Zum Glück besteht die Lösung aus einem einzigen Befehl.
Zertifikat ausstellen, das Browser akzeptieren: ein Befehl
OpenSSL unterstützt das Flag -addext seit Version 1.1.1. Sie benötigen daher keine umständlichen Konfigurationsdateien mehr, wie sie ältere Anleitungen zum Einfügen eines SAN verwendet haben. Unter Ubuntu 24.04:
sudo openssl req -x509 -newkey rsa:4096 -sha256 -days 730 -noenc \
-keyout /etc/ssl/private/git.internal.key \
-out /etc/ssl/certs/git.internal.crt \
-subj "/CN=git.internal.lan" \
-addext "subjectAltName=DNS:git.internal.lan,IP:10.8.0.1"Funktion der einzelnen Flags:
-x509erstellt direkt ein selbstsigniertes Zertifikat statt einer Zertifikatsanforderung.-newkey rsa:4096erzeugt im selben Schritt einen neuen Schlüssel. RSA 4096 verursacht bei keinem alten Client Probleme. Wenn alle Verbindungen von modernen Clients stammen, ist-newkey ec -pkeyopt ec_paramgen_curve:P-256kleiner und schneller.-noencist die Schreibweise von OpenSSL 3.x für das frühere-nodes: Der Schlüssel hat keine Passphrase. Beide Schreibweisen funktionieren. Bei einem Schlüssel mit Passphrase wartet nginx bei jedem Start auf eine Eingabe. Für einen Serverschlüssel sollten Sie daher dieses Flag verwenden.-days 730gilt für zwei Jahre. Weitere Informationen zu diesem Wert finden Sie im Abschnitt zum Ablaufdatum.-subjbeantwortet die interaktiven Fragen direkt in der Befehlszeile. Der CN ist inzwischen nur noch kosmetisch relevant. Setzen Sie ihn trotzdem auf den primären Namen, da einige Tools ihn anzeigen.-addext "subjectAltName=..."ist das entscheidende Flag. Führen Sie jeden Namen und jede IP-Adresse auf, die Clients eingeben werden:DNS:-Einträge für Hostnamen (Wildcards wieDNS:*.internal.lansind zulässig) undIP:-Einträge für Adressen. Wenn jemandhttps://10.8.0.1aufrufen soll, muss der EintragIP:10.8.0.1vorhanden sein. Ein SAN nur für DNS-Namen führt andernfalls erneut zuNET::ERR_CERT_COMMON_NAME_INVALID.
Prüfen Sie, ob das SAN tatsächlich übernommen wurde, bevor Sie weitere Konfigurationen vornehmen:
openssl x509 -in /etc/ssl/certs/git.internal.crt -noout -ext subjectAltNameKorrekte Ausgabe:
X509v3 Subject Alternative Name:
DNS:git.internal.lan, IP Address:10.8.0.1Wenn stattdessen No extensions in certificate ausgegeben wird, enthält das Zertifikat kein SAN. Browser lehnen es ab. Erzeugen Sie das Zertifikat neu, statt fortzufahren.
Sichern Sie den Schlüssel unerquicklich
Ein privater Schlüssel, den jeder Benutzer auf dem System lesen kann, ist kein privater Schlüssel. Auf einem unveränderten Ubuntu-24.04-System ist /etc/ssl/private bereits 700 root:root, sodass nur root den Inhalt überhaupt auflisten kann. 710 root:ssl-cert wird es erst, wenn etwas das Paket ssl-cert installiert hat (apache2 empfiehlt dieses Paket). Setzen Sie die Berechtigungen der Datei in jedem Fall ausdrücklich:
sudo chown root:root /etc/ssl/private/git.internal.key
sudo chmod 600 /etc/ssl/private/git.internal.keynginx und Apache lesen Zertifikate als root ein, bevor sie ihre Berechtigungen reduzieren. Daher funktioniert für sie der Modus 600 bei root:root. Wenn der Schlüssel für einen Dienst bestimmt ist, der unter einem eigenen Benutzer läuft und den Schlüssel selbst lädt, beispielsweise eine Node-Anwendung, Gitea oder ein Python-Daemon, übertragen Sie chown stattdessen an diesen Dienstbenutzer. Verwenden Sie weiterhin den Modus 600. Was Sie niemals tun: den Modus 644 verwenden, eine Kopie in einem Git-Repository ablegen oder eine Kopie in /tmp speichern.
In nginx einbinden
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name git.internal.lan;
ssl_certificate /etc/ssl/certs/git.internal.crt;
ssl_certificate_key /etc/ssl/private/git.internal.key;
location / {
proxy_pass http://127.0.0.1:3000;
}
}sudo nginx -t && sudo systemctl reload nginxnginx -t muss syntax is ok und test is successful ausgeben, bevor der Reload wirksam wird. Gibt es stattdessen SSL_CTX_use_PrivateKey_file() failed ... key values mismatch aus, stammen Zertifikat und Schlüssel aus zwei unterschiedlichen Generierungsläufen. Siehe den Abschnitt zu Fehlerbildern.
In Apache einbinden
sudo a2enmod ssl proxy proxy_httpssl allein reicht hier nicht aus: Der folgende Vhost verwendet ProxyPass. Ohne mod_proxy und mod_proxy_http schlägt der Konfigurationstest mit Invalid command 'ProxyPass', perhaps misspelled or defined by a module not included in the server configuration fehl. Speichern Sie den Vhost als /etc/apache2/sites-available/git-internal.conf:
<VirtualHost *:443>
ServerName git.internal.lan
SSLEngine on
SSLCertificateFile /etc/ssl/certs/git.internal.crt
SSLCertificateKeyFile /etc/ssl/private/git.internal.key
ProxyPass / http://127.0.0.1:3000/
ProxyPassReverse / http://127.0.0.1:3000/
</VirtualHost>sudo a2ensite git-internal
sudo apache2ctl configtest && sudo systemctl reload apache2configtest sollte auf Syntax OK antworten. Testen Sie nun von einem Clientcomputer aus:
curl -v https://git.internal.lan/Daraufhin erhalten Sie einen Fehler:
curl: (60) SSL certificate problem: self-signed certificateDas ist kein Fehler in der Konfiguration. TLS funktioniert wie vorgesehen: curl kennt Ihr Zertifikat nicht und verweigert die Verbindung zu einem Server, den es nicht authentifizieren kann. Der nächste Abschnitt beschreibt die eigentliche Lösung. Sie entspricht nicht dem Vorgehen, das derzeit im halben Internet verwendet wird.
Clients diesem Zertifikat vertrauen lassen und zu vermeidende Anti-Patterns
Zuerst die falschen Lösungen, klar als solche benannt. curl -k (oder --insecure) in einem Script, verify=False in Python requests und NODE_TLS_REJECT_UNAUTHORIZED=0 in Node sorgen nicht dafür, dass Ihrem Zertifikat vertraut wird. Sie schalten die Zertifikatsprüfung aus. Dadurch kommuniziert der Client problemlos mit jedem Server, der ein beliebiges Zertifikat vorlegt, einschließlich eines Zertifikats, das ein Angreifer in den Verbindungsweg eingeschleust hat. Der TLS-Overhead bleibt bestehen, aber die Authentifizierung, der TLS überhaupt dient, entfällt. Schlimmer noch: Diese Flags verbreiten sich weiter. Sie werden in einen Cronjob kopiert, anschließend in ein Deploy-Script und später in Produktivcode. Irgendwann weiß niemand mehr, welche Verbindungen nur vorübergehend ohne Prüfung laufen sollten. Wenn ein verify=False über die Debugging-Sitzung hinaus bestehen bleibt, durch die er entstanden ist, ist der Entwurf falsch.
Die richtige Lösung besteht darin, dem Betriebssystem jedes Clients beizubringen, dass dieses Zertifikat eine vertrauenswürdige Root-Zertifizierungsstelle ist. Auf Ubuntu- und Debian-Clients:
sudo cp git.internal.crt /usr/local/share/ca-certificates/git.internal.crt
sudo update-ca-certificatesDie relevante Zeile in der Ausgabe (darauf folgt ein Block vom Typ Running hooks in /etc/ca-certificates/update.d...):
Updating certificates in /etc/ssl/certs...
1 added, 0 removed; done.In diesen Zeilen verbergen sich zwei mögliche Fehlerquellen. Die Datei muss mit .crt enden. Eine Erweiterung vom Typ .pem wird stillschweigend ignoriert, und Sie erhalten 0 added ohne Fehlermeldung. Außerdem muss der Inhalt im PEM-Format vorliegen. Die Datei beginnt mit -----BEGIN CERTIFICATE-----. Eine DER-Binärdatei konvertieren Sie zuerst mit openssl x509 -inform der -in file.der -out file.crt. Das Hinzufügen des selbstsignierten Zertifikats selbst als Root funktioniert, weil ein selbstsigniertes Zertifikat seine eigene Root-Zertifizierungsstelle ist.
Danach vertrauen curl, wget, git, apt und alle anderen Programme, die OpenSSL mit dem System-Bundle verwenden, dem Server ohne zusätzliche Flags. Einige Clients verwalten eigene Truststores und benötigen eine individuelle Konfiguration:
- Chrome/Chromium unter Linux liest eine NSS-Datenbank statt des System-Stores:
sudo apt install libnss3-toolsund anschließend pro Benutzercertutil -d sql:$HOME/.local/share/pki/nssdb -A -t "C,," -n "git.internal" -i git.internal.crt. Dieser Pfad ist seit Version 146 der Standard von Chrome. Wenn der Benutzer noch eine ältere~/.pki/nssdbaus einer früheren Installation besitzt, liest Chrome stattdessen weiterhin diese Datei. Verweisen Sie auf diesen Systemen daher mit-daufsql:$HOME/.pki/nssdb. - Firefox verfügt über einen eigenen Store: Settings → Privacy & Security → Certificates → Import. Unter Windows und macOS können Sie stattdessen in
about:configsecurity.enterprise_roots.enabledauftruesetzen, damit Firefox den Store des Betriebssystems verwendet. Mozilla dokumentiert diese Einstellung für Windows und macOS, nicht für Linux. Verwenden Sie unter Ubuntu daher den Import. - Python requests wird mit einem eigenen CA-Bundle (certifi) ausgeliefert und ignoriert den System-Store: Übergeben Sie
verify="/usr/local/share/ca-certificates/git.internal.crt"oder exportieren SieREQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt. - Node.js verwendet standardmäßig eigene mitgelieferte Root-Zertifikate: Exportieren Sie
NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/git.internal.crt. Alternativ können Sie Node.js mit dem Flag--use-system-ca(Node 23.9 und höher unter Linux) oderNODE_USE_SYSTEM_CA=1(Node 24.6 sowie 22.19 und höher) anweisen, den gerade aktualisierten System-Store zu verwenden.
Klicken Sie auf Windows-Clients doppelt auf die .crt und installieren Sie sie unter Trusted Root Certification Authorities. Fügen Sie sie unter macOS in Keychain Access zum System-Schlüsselbund hinzu und markieren Sie sie als Always Trust.
Eine Root-CA für viele Dienste: eine kleine private CA
Zertifikatsbasierte Vertrauensstellungen skalieren sofort schlecht: sechs Dienste multipliziert mit vier Client-Computern ergeben 24 Vertrauensinstallationen, und jeder neue Dienst erhöht den Aufwand. Die Lösung ist eine private CA. Die Clients vertrauen einer Root-CA, und Sie signieren damit das Zertifikat jedes Dienstes.
Die unkomplizierte Option ist mkcert. Das Paket ist in den Ubuntu-24.04-Repositories enthalten und verarbeitet die NSS-Speicher von Firefox und Chrome mit einer weiter unten beschriebenen Einschränkung, die update-ca-certificates nicht abdeckt:
sudo apt install -y mkcert libnss3-tools
mkcert -install
mkcert git.internal.lan "*.internal.lan" 10.8.0.1mkcert -install erstellt eine Root-CA und registriert sie im System-Speicher, in den gefundenen NSS-Speichern der Browser sowie im Java-Speicher, wenn JAVA_HOME gesetzt ist. Node liest den System-Speicher nicht automatisch. Starten Sie Node-Anwendungen daher wie oben mit --use-system-ca oder NODE_USE_SYSTEM_CA=1, oder exportieren Sie NODE_EXTRA_CA_CERTS="$(mkcert -CAROOT)/rootCA.pem". Der dritte Befehl erzeugt git.internal.lan+2.pem und git.internal.lan+2-key.pem. Beide Dateien können Sie in die oben genannten nginx- oder Apache-Snippets übernehmen. Das Programm ist für einen Entwicklungscomputer ausgelegt. Der Root-Schlüssel liegt auf dem Computer, auf dem -install ausgeführt wurde. Deshalb eignet sich diese Lösung sehr gut für einen Entwicklungs-Laptop, aber nicht für eine Serverflotte.
Die Einschränkung besteht im Oktober 2026 darin, dass mkcert die NSS-Datenbank von Chrome nur unter dem älteren Pfad ~/.pki/nssdb sucht, nicht unter ~/.local/share/pki/nssdb. Chrome verwendet ~/.local/share/pki/nssdb seit Version 146 standardmäßig. Wenn auf einem Computer keine ältere Datenbank vorhanden ist, fügen Sie die Root-CA für Chrome selbst hinzu. Verwenden Sie dazu den Befehl certutil aus dem vorherigen Abschnitt und -i "$(mkcert -CAROOT)/rootCA.pem".
Für Server erledigt einfaches OpenSSL die gesamte CA-Erstellung mit fünf Befehlen:
openssl genrsa -out lab-ca.key 4096
openssl req -x509 -new -key lab-ca.key -sha256 -days 3650 \
-out lab-ca.crt -subj "/CN=Lab Internal CA" \
-addext "basicConstraints=critical,CA:TRUE,pathlen:0" \
-addext "keyUsage=critical,keyCertSign,cRLSign"
openssl genrsa -out git.key 2048
openssl req -new -key git.key -out git.csr -subj "/CN=git.internal.lan" \
-addext "subjectAltName=DNS:git.internal.lan,IP:10.8.0.1"
openssl x509 -req -in git.csr -CA lab-ca.crt -CAkey lab-ca.key \
-CAcreateserial -days 730 -sha256 -copy_extensions copy -out git.crtDie wichtige Falle steckt im letzten Befehl: openssl x509 -req entfernt standardmäßig alle Erweiterungen aus der CSR, einschließlich des sorgfältig hinzugefügten SAN. -copy_extensions copy übernimmt die Erweiterungen. Diese Option ist in OpenSSL 3.x enthalten und funktioniert daher unter 24.04. Ohne diese Option enthält das signierte Zertifikat kein SAN, und Chrome zeigt erneut NET::ERR_CERT_COMMON_NAME_INVALID an. Prüfen Sie das Ergebnis mit derselben openssl x509 -noout -ext subjectAltName-Prüfung wie zuvor.
Verteilen Sie lab-ca.crt einmalig pro Computer über die oben beschriebenen Schritte für den Trust Store an die Clients. Schützen Sie lab-ca.key jetzt besonders sorgfältig: Verwenden Sie den Modus 600. Bewahren Sie die Datei möglichst auf einem Computer auf, der nicht zu den Servern gehört, für die Sie Zertifikate signieren. Jeder, der diesen Schlüssel besitzt, kann ein Zertifikat für jeden Namen ausstellen, dem Ihre Clients vertrauen.
Ablauf und Rotation
Die Gültigkeitsdauer öffentlich vertrauenswürdiger CA-Zertifikate sinkt. Das CA/Browser Forum hat die Gültigkeitsdauer neu ausgestellter, öffentlich vertrauenswürdiger Zertifikate im März 2026 auf 200 Tage begrenzt, nachdem zuvor 398 Tage galten. 2027 sinkt sie auf 100 Tage und bis März 2029 auf 47 Tage. Diese Regeln gelten jedoch für öffentlich vertrauenswürdige CAs. Ihre private CA unterliegt ihnen nicht. Browser setzen diese Vorgaben bei manuell installierten Root-Zertifikaten ebenfalls nicht durch. Eine praktische Einschränkung gilt dennoch: Apple-Plattformen lehnen TLS-Serverzertifikate mit einer Gültigkeitsdauer von mehr als 825 Tagen ab, unabhängig vom Aussteller. Wenn eine Verbindung von iPhones oder Macs aus erfolgt, sollten Leaf-Zertifikate daher höchstens zwei Jahre gültig sein. -days 730 erfüllt diese Vorgabe überall. Eine zehn Jahre gültige Root-CA mit zwei Jahre gültigen Leaf-Zertifikaten ist eine passende interne Struktur.
Lang gültige Zertifikate fallen nur auf eine Weise aus: still und gleichzeitig an einem Datum, das niemand mehr im Blick hat. Prüfen Sie Ihre Zertifikate:
openssl x509 -in /etc/ssl/certs/git.internal.crt -noout -enddateTragen Sie die Erneuerung in einen Kalender ein, oder lassen Sie sich 30 Tage vorher von cron erinnern. openssl x509 -checkend 2592000 -in cert.crt beendet sich mit einem Fehlercode, sobald der Ablauf innerhalb der angegebenen Anzahl von Sekunden liegt. Wenn Sie bereits Uptime Kuma zur Statusüberwachung einsetzen, melden dessen HTTPS-Monitore eine bevorstehende Zertifikatsablaufzeit kostenlos.
Die Rotation mit einer privaten CA ist angenehm unspektakulär: Führen Sie die CSR- und Signierbefehle erneut aus, tauschen Sie die Dateien aus und laden Sie den Webserver neu. Die Root-CA hat sich nicht geändert. Daher bemerkt kein Client etwas.
Fehlerbilder und die angezeigten Meldungen
NET::ERR_CERT_AUTHORITY_INVALID ist der erwartete Zustand, bevor Sie die Vertrauensstellung einrichten. Es handelt sich nicht um einen Zertifikatsfehler. Wenn die Meldung nach der Installation der Root-CA bestehen bleibt: Unter Linux verwendet Chrome NSS statt des System-Zertifikatsspeichers (siehe Schritt certutil). Seit Chrome 146 befindet sich diese Datenbank unter ~/.local/share/pki/nssdb, sofern kein veraltetes ~/.pki/nssdb vorhanden ist. Eine Root-CA, die dem anderen Pfad hinzugefügt wurde, wird daher nie gefunden. Möglich ist auch, dass die kopierte Datei nicht mit .crt endete und update-ca-certificates den Wert 0 added meldete. Oder der Server liefert ein anderes Zertifikat aus als das, dem Sie vertraut haben. Vergleichen Sie die Fingerabdrücke mit openssl s_client -connect git.internal.lan:443 </dev/null 2>/dev/null | openssl x509 -noout -fingerprint -sha256.
NET::ERR_CERT_COMMON_NAME_INVALID bedeutet, dass das Zertifikat kein SAN enthält oder dass das SAN den Namen in der Adressleiste nicht abdeckt. Der klassische Fall: Das SAN enthält DNS:git.internal.lan, aber der Benutzer hat https://10.8.0.1 aufgerufen. Änderungen am Zertifikatsspeicher können diesen Fehler nicht beheben. Stellen Sie das Zertifikat mit dem fehlenden Eintrag neu aus.
curl: (60) SSL certificate problem: self-signed certificate bedeutet, dass curl dem Zertifikat nicht vertraut. Die Variante self-signed certificate in certificate chain hat bei einem von Ihrer privaten CA signierten Zertifikat dieselbe Bedeutung. Als einmalige Lösung verwenden Sie curl --cacert lab-ca.crt https://.... Als dauerhafte Lösung konfigurieren Sie den Truststore. Verwenden Sie nicht -k.
unable to load certificate ... Expecting: TRUSTED CERTIFICATE (oder Expecting: CERTIFICATE REQUEST oder no start line) weist auf eine PEM-Verwechslung hin. Sie haben OpenSSL den falschen Dateityp übergeben: einen Schlüssel oder eine CSR, obwohl ein Zertifikat erwartet wurde, oder eine DER-Binärdatei, obwohl PEM erwartet wurde. head -1 filename zeigt, was tatsächlich vorliegt. Ein Zertifikat beginnt mit -----BEGIN CERTIFICATE-----. Für DER konvertieren Sie die Datei mit openssl x509 -inform der -in file.der -out file.crt.
nginx: [emerg] SSL_CTX_use_PrivateKey_file(...) failed (SSL: error ... key values mismatch) bedeutet, dass Zertifikat und Schlüssel nicht zusammengehören. Ursache ist meistens, dass der Generierungsbefehl zweimal ausgeführt und die Dateien anschließend vermischt wurden. Prüfen Sie openssl x509 -in git.internal.crt -noout -pubkey | sha256sum und openssl pkey -in git.internal.key -pubout | sha256sum. Übereinstimmende Hashes weisen auf ein zusammengehöriges Paar hin. Bei unterschiedlichen Hashes müssen Sie beide Dateien gemeinsam neu erzeugen.
FAQ
Warum zeigt Chrome nach dem Erstellen eines selbstsignierten Zertifikats weiterhin „Nicht sicher“ an?
Wenn der Fehler NET::ERR_CERT_AUTHORITY_INVALID lautet, ist das Zertifikat in Ordnung. Chrome hat lediglich noch keinen Grund, ihm zu vertrauen. Installieren Sie es oder die Root-CA Ihrer privaten CA im Truststore des Clients. Beachten Sie außerdem, dass Chrome unter Linux die NSS-Datenbank über certutil verwendet, unter ~/.local/share/pki/nssdb seit Chrome 146 oder über ein vorhandenes älteres ~/.pki/nssdb, nicht den System-Truststore. Wenn der Fehler NET::ERR_CERT_COMMON_NAME_INVALID lautet, fehlt dem Zertifikat ein Subject Alternative Name, der zur URL passt. Das Zertifikat muss mit -addext "subjectAltName=..." neu ausgestellt werden.
Wie kann curl einem selbstsignierten Zertifikat ohne -k vertrauen?
Kopieren Sie das Zertifikat im PEM-Format mit der Erweiterung .crt nach /usr/local/share/ca-certificates/ und führen Sie sudo update-ca-certificates aus. Die Ausgabe muss 1 added lauten. Danach prüft curl das Zertifikat wie jedes öffentlich vertrauenswürdige Zertifikat. Für eine einmalige Anfrage, ohne den System-Truststore zu ändern, prüft curl --cacert /path/to/cert.crt ausschließlich gegen diese Datei. -k deaktiviert die Prüfung vollständig und darf nicht in Skripten verwendet werden.
Wie lange kann ein selbstsigniertes Zertifikat gültig sein?
Technisch können Sie eine beliebige Gültigkeitsdauer wählen. Die Beschränkungen des CA/Browser Forum, derzeit 200 Tage und bis 2029 47 Tage, gelten für öffentlich vertrauenswürdige CAs, nicht für private Truststores. In der Praxis sollten Sie Serverzertifikate auf 825 Tage begrenzen, weil Apple-Geräte unabhängig vom Aussteller Zertifikate mit längerer Gültigkeit ablehnen. Eine zehn Jahre gültige private Root-CA mit zweijährigen (-days 730) Leaf-Zertifikaten ist ein sinnvoller Standard. Planen Sie die Erneuerung trotzdem ein, denn ein abgelaufenes internes Zertifikat kann an einem vergessenen Datum unbemerkt alle Dienste außer Betrieb setzen.
Sollte ich ein selbstsigniertes Zertifikat oder Let's Encrypt verwenden?
Wenn der Dienst einen öffentlichen DNS-Namen hat und aus dem Internet erreichbar ist, sollten Sie immer Let's Encrypt verwenden: kostenlos, automatisiert und von den meisten Browsern und Betriebssystemen bereits als vertrauenswürdig eingestuft. Prüfen Sie die Kompatibilitätsliste von Let's Encrypt, wenn sehr alte Geräte eine Verbindung herstellen müssen. Selbstsignierte Zertifikate oder eine private CA sind für Fälle gedacht, in denen Let's Encrypt keine Zertifikate ausstellen kann: private IPs, rein interne Hostnamen wie .lan, vom Internet getrennte Netzwerke und Dienste, die bewusst hinter einem VPN verborgen werden. Die Entscheidung hängt von Erreichbarkeit und Namensgebung ab, nicht von der kryptografischen Sicherheit. Die Kryptografie ist identisch.
Warum wird mein Zertifikat abgelehnt, obwohl ich es zu /usr/local/share/ca-certificates hinzugefügt habe?
Prüfen Sie drei Dinge. Die Datei muss mit .crt enden. Eine Erweiterung .pem wird stillschweigend übersprungen, und update-ca-certificates meldet 0 added. Der Inhalt muss PEM-Text sein und mit -----BEGIN CERTIFICATE----- beginnen, nicht eine DER-Binärdatei. Außerdem muss die Anwendung tatsächlich den System-Truststore verwenden. Chrome unter Linux, Firefox, Python requests, Node.js, sofern es nicht mit --use-system-ca gestartet wurde, und Java verwalten jeweils einen eigenen Truststore. Das Zertifikat muss dort separat hinzugefügt werden.