Certbot für Nginx auf Ubuntu 24.04 installieren
Installieren Sie Certbot unter Ubuntu 24.04 via apt oder snap. Erfahren Sie, wie Sie Let's Encrypt Zertifikate einrichten und den Port 80 Timeout bei der Erneuerung vermeiden.
Certbot installieren: apt oder snap
Unter Ubuntu 24.04 stellt sudo apt install certbot python3-certbot-nginx einen funktionsfähigen Certbot bereit, der echte, öffentlich vertrauenswürdige Let's Encrypt-Zertifikate ausstellt. Die Upstream-Dokumentation von Certbot verweist stattdessen auf den snap; der Unterschied ist geringfügig: Der snap folgt den Upstream-Releases, während das Archiv-Paket die mit der LTS-Version ausgelieferte Version enthält und Sicherheitsupdates erhält.
Entscheiden Sie sich für eine Variante. Zwei Certbot-Installationen bedeuten zwei Erneuerungs-Timer, die auf denselben /etc/letsencrypt-Baum zugreifen. Die Installation, die Sie vergessen, wird diejenige sein, die Sie später überrascht.
Der apt-Weg:
sudo apt update
sudo apt install certbot python3-certbot-nginxDies installiert /usr/bin/certbot, das nginx-Plugin, ein certbot.service- und certbot.timer-Paar sowie einen /etc/cron.d/certbot-Eintrag, der unter systemd keine Funktion hat.
Der snap-Weg:
sudo apt remove certbot python3-certbot-nginx
sudo snap install core && sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbotDer snap liefert seinen eigenen Timer, snap.certbot.renew.timer, mit. Entfernen Sie das apt-Paket, bevor Sie den snap installieren.
Beide Installationen verhalten sich danach identisch. Certbot 2.x verwendet standardmäßig ECDSA (P-256)-Schlüssel. Übergeben Sie --key-type rsa nur für Clients, die kein ECDSA unterstützen. Der gesamte Status befindet sich unter /etc/letsencrypt: archive/ enthält die eigentlichen Schlüssel- und Zertifikatsdateien, live/ enthält symbolische Links auf die aktuellen Dateien, renewal/ enthält eine Konfigurationsdatei pro Zertifikat und accounts/ enthält Ihren ACME-Account-Schlüssel.
Was HTTP-01 tatsächlich bewirkt und warum Port 80 nicht optional ist
Die HTTP-01-Challenge ist ein Rückrufverfahren. Sie fordern bei Let's Encrypt ein Zertifikat für example.com an; der Dienst löst den Namen im öffentlichen DNS auf, baut eine Verbindung zu Port 80 unter der gefundenen Adresse auf und fragt http://example.com/.well-known/acme-challenge/<token> ab. Ihr Server antwortet mit dem exakten Token-Inhalt, den Certbot zuvor auf die Festplatte geschrieben hat. Das ist der gesamte Mechanismus. Daraus ergeben sich drei Konsequenzen, die für die meisten fehlgeschlagenen Zertifikatsausstellungen verantwortlich sind.
- Port 80 muss aus dem öffentlichen Internet erreichbar sein, nicht nur von Ihrem Laptop aus. Eine
ufw-Regel, eine Security Group des Cloud-Anbieters oder eine Firewall in der VPS-Konsole, die nur Port 443 öffnet, verhindert die Ausstellung und damit auch jede zukünftige Erneuerung. - DNS muss bereits auf diesen Server zeigen. Der Validierungsserver führt seine eigene Abfrage von außen durch; Ihre
/etc/hosts-Einträge und der Browser-Cache spielen für ihn keine Rolle. - Wenn Sie einen AAAA-Record veröffentlichen, wird zuerst IPv6 versucht. Let's Encrypt versucht es erneut über IPv4, wenn die IPv6-Verbindung komplett fehlschlägt. Ein veralteter AAAA-Record, der auf einen Host zeigt, der die Verbindung akzeptiert und etwas anderes ausliefert, führt jedoch zu einem harten Fehler.
Weiterleitungen sind zulässig: Die Validierung folgt einer HTTP-Weiterleitung zu HTTPS und stört sich nicht daran, dass das Zertifikat am Ziel fehlt, abgelaufen ist oder selbstsigniert wurde. Was der Dienst jedoch nicht tut, ist an einem anderen Port als Port 80 zu starten. Certbot verfügt über keine TLS-ALPN-01-Implementierung, daher ist "einfach Port 443 nutzen" kein Ausweg.
Wahl eines Authenticators: --nginx, --webroot, --standalone
--nginx ist die richtige Standardwahl, wenn nginx bereits läuft und die Domain ausliefert. Certbot analysiert Ihre Konfiguration, fügt einen temporären Challenge-Pfad hinzu, lädt nginx neu, validiert und schreibt anschließend die TLS-Direktiven in Ihren Server-Block. Dies geschieht ohne Ausfallzeit.
sudo certbot --nginx -d example.com -d www.example.comSkriptgesteuert, für ein frisches System:
sudo certbot --nginx \
-d example.com -d www.example.com \
--agree-tos -m ops@example.com --no-eff-email \
--redirect --non-interactive--webroot ist die richtige Wahl, wenn Certbot Ihre nginx-Konfiguration nicht verändern soll, etwa weil Sie diese aus einer Vorlage generieren, in git verwalten oder per Ansible verteilen. Certbot schreibt lediglich die Challenge-Datei in ein Verzeichnis, das bereits von Ihnen ausgeliefert wird.
sudo certbot certonly --webroot -w /var/www/example.com \
-d example.com -d www.example.com \
--deploy-hook "systemctl reload nginx"--standalone ist die richtige Wahl, wenn kein Dienst auf Port 80 lauscht: beispielsweise bei einem Mailserver, einer API, die nur über 443 kommuniziert, oder einem Initialisierungsskript, das vor der Installation von nginx ausgeführt wird. Certbot belegt Port 80 für wenige Sekunden selbst. Falls nginx bereits läuft, schlägt dies fehl; stoppen Sie den Dienst daher vor der Ausführung:
sudo certbot certonly --standalone -d mail.example.com \
--pre-hook "systemctl stop nginx" \
--post-hook "systemctl start nginx"Diese Hooks werden in der Erneuerungskonfiguration des Zertifikats gespeichert, sodass derselbe Stopp- und Startvorgang bei der automatischen Erneuerung ohne manuelles Eingreifen erfolgt.
Ein Server-Block, der vor und nach der Zertifikatserstellung funktioniert
Das Henne-Ei-Problem: nginx verweigert den Start, wenn ssl_certificate auf eine Datei verweist, die nicht existiert, und Certbot kann keine Validierung durchführen, während nginx nicht läuft. Nehmen Sie die Website zuerst auf Port 80 in Betrieb.
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/example.com;
index index.html;
location ^~ /.well-known/acme-challenge/ {
root /var/www/example.com;
default_type "text/plain";
try_files $uri =404;
}
location / {
try_files $uri $uri/ =404;
}
}Führen Sie sudo nginx -t && sudo systemctl reload nginx aus, stellen Sie sicher, dass curl -I http://example.com/ von außerhalb des Servers antwortet, und führen Sie dann die Ausstellung durch. Danach:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
location ^~ /.well-known/acme-challenge/ {
root /var/www/example.com;
default_type "text/plain";
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
root /var/www/example.com;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}Das Präfix ^~ für den ACME-Pfad ist essenziell: Es verhindert, dass der return 301-Block die Challenge-Anfrage abfängt. Wenn dieser Pfad auf Port 80 erhalten bleibt, funktionieren Erneuerungen auch dann, wenn der Rest der Website nur noch über HTTPS erreichbar ist.
Beide oben genannten Blöcke liefern Dateien von der Festplatte aus; wenn nginx stattdessen als Frontend für eine Anwendung dient, wird location / zu einem proxy_pass-Block und der Reverse-Proxy-Server-Block, Zeile für Zeile behandelt die Header, die diese Anwendung benötigt, während der ACME-Pfad und die TLS-Direktiven unverändert bleiben.
Die HTTP/2-Syntax hängt von Ihrer nginx-Version ab; das Vermischen beider Formen führt zu einem Startfehler. Ubuntu 24.04 liefert nginx 1.24, das die Angabe inline als listen 443 ssl http2; erwartet. Debian 13 liefert ein neueres nginx, das die separate http2 on;-Direktive erfordert. Prüfen Sie dies zuerst mit nginx -v.
Verweisen Sie nginx auf live/, niemals auf archive/. Die live/-Symlinks werden bei jeder Erneuerung aktualisiert; ein fester Pfad in archive/ würde Sie an ein Zertifikat binden, das abläuft, ohne dass es automatisch aktualisiert wird.
Wildcards erfordern DNS-01, und DNS-01 erfordert ein Plugin
Ein Wildcard-Zertifikat (*.example.com) kann nicht über HTTP-01 validiert werden, da es keinen einzelnen Hostnamen gibt, von dem eine Datei abgerufen werden könnte. DNS-01 ist der einzige Weg: Sie beweisen die Kontrolle, indem Sie einen _acme-challenge.example.com TXT-Record veröffentlichen. Certbot benötigt API-Zugangsdaten für Ihren DNS-Anbieter, um dies automatisiert durchzuführen; genau dafür existieren die Anbieter-Plugins. Die vollständige Anleitung für Wildcard-Zertifikate behandelt die Mechanismen der TXT-Records und die Erneuerungsfalle im manuellen Modus; die kurze Cloudflare-Version folgt hier.
sudo snap set certbot trust-plugin-with-root=ok
sudo snap install certbot-dns-cloudflareAuf dem apt-Pfad ist dies stattdessen sudo apt install python3-certbot-dns-cloudflare. Die Zugangsdaten gehören in eine Datei, die nur für root lesbar ist:
# /root/.secrets/cloudflare.ini
# then: sudo chmod 600 /root/.secrets/cloudflare.ini
dns_cloudflare_api_token = your_scoped_token_hereBeschränken Sie das Token auf DNS-Bearbeitungsrechte für diese eine Zone. Es ist ein kryptografischer Schlüssel für Ihr DNS; behandeln Sie ihn auch so.
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
-d example.com -d '*.example.com'Setzen Sie den Wildcard-Eintrag in Anführungszeichen, damit die Shell ihn nicht als Glob-Muster interpretiert. DNS-01 löst zudem Probleme, die mit HTTP-01 nicht lösbar sind: Zertifikate für Hosts ohne öffentlichen Port 80, einen internen Dienst, einen Server, der nur über ein selbst gehostetes WireGuard VPN auf einem VPS erreichbar ist, oder ein Admin-Panel auf einer privaten Schnittstelle.
Erneuerung: Die 90 Tage, der Timer, der Deploy-Hook
Let's-Encrypt-Zertifikate sind 90 Tage lang gültig. Certbot erneuert sie, wenn weniger als 30 Tage verbleiben. Dies lässt Ihnen ein 30-Tage-Fenster, in dem eine fehlerhafte Erneuerung ein behebbares Ärgernis und kein Ausfall ist. Let's Encrypt versendet keine E-Mails mehr zur Warnung vor dem Ablauf; niemand wird Sie darauf hinweisen, daher liegt die Überwachung nun in Ihrer Verantwortung.
Überprüfen Sie den Timer, der mit Ihrer Installation ausgeliefert wurde:
systemctl list-timers 'certbot*' 'snap.certbot*'
sudo certbot certificatescertbot renew durchläuft jede Konfiguration in /etc/letsencrypt/renewal/, überspringt alle Zertifikate außerhalb des 30-Tage-Fensters und erneuert den Rest exakt mit den Flags des ursprünglichen Laufs. Deshalb ist der erste Lauf entscheidend: Er ist derjenige, der aufgezeichnet wird.
Das Erneuern der Datei auf dem Datenträger ändert von sich aus nichts; nginx liefert das alte Zertifikat weiterhin aus dem Arbeitsspeicher aus, bis es angewiesen wird, neu zu laden. Richten Sie einmalig einen Deploy-Hook ein:
sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh >/dev/null <<'EOF'
#!/bin/sh
set -e
nginx -t && systemctl reload nginx
EOF
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.shAlles, was in renewal-hooks/deploy/ ausführbar ist, wird nach jeder erfolgreichen Erneuerung ausgeführt. Das Flag --deploy-hook erledigt dieselbe Aufgabe für ein einzelnes Zertifikat und speichert renew_hook = ... in dessen Erneuerungskonfiguration. certbot --nginx führt das Neuladen für Sie durch; --webroot- und --standalone-Setups tun dies nicht. Ein fehlender Hook ist genau der Grund, warum eine Website ein abgelaufenes Zertifikat ausliefert, während certbot certificates fröhlich ein frisches meldet. Alles andere, das das Zertifikat beim Start liest, benötigt denselben Hook. Eine containerisierte Anwendung, wie etwa eine Nextcloud VPS-Installation mit Docker, TLS und Backups, benötigt hier ebenfalls einen eigenen Neustart- oder Neuladeschritt.
Testen der Erneuerung unter Realbedingungen
sudo certbot renew --dry-runDieser Befehl führt den vollständigen Challenge-Prozess gegen die Staging-Umgebung von Let's Encrypt aus: Er nutzt denselben Codepfad, dieselben Firewall-Regeln, dasselbe DNS, verursacht keine Kosten durch Rate-Limits und schreibt keine Daten auf den Datenträger. Wenn der Test heute erfolgreich ist, wird auch die automatisierte Erneuerung in 60 Tagen funktionieren, sofern sich die Konfiguration des Servers in der Zwischenzeit nicht ändert.
Ein Trockenlauf beweist nicht, dass Ihr Reload-Hook korrekt ausgeführt wird, da sich das Verhalten je nach Certbot-Version unterscheidet. Testen Sie diesen Teil manuell: Führen Sie das Hook-Skript direkt aus, bestätigen Sie, dass systemctl reload nginx erfolgreich ist, und prüfen Sie sudo grep renew_hook /etc/letsencrypt/renewal/example.com.conf.
Die Fehler, auf die Sie tatsächlich stoßen werden
Could not bind to IPv4 or IPv6., --standalone während nginx bereits Port 80 belegt. Verwenden Sie --nginx oder --webroot oder stoppen Sie nginx während der Ausführung. Bestätigen Sie den Prozess, der den Port belegt, mit sudo ss -lntp | grep ':80'.
Timeout during connect (likely firewall problem), Let's Encrypt konnte Port 80 nicht erreichen. Prüfen Sie von außen nach innen: sudo ufw status (öffnen Sie ihn mit sudo ufw allow 'Nginx Full'), dann die Firewall des VPS-Anbieters und schließlich das DNS. Testen Sie von einem Ort aus, der nicht Ihr Server ist: curl -sSv http://example.com/.well-known/acme-challenge/test. Ein veralteter AAAA-Eintrag erzeugt dieselbe Meldung.
unauthorized :: Invalid response from http://example.com/.well-known/acme-challenge/xyz: 404, Port 80 ist erreichbar, aber das Token wird nicht ausgeliefert. Die Anfrage landete in einem anderen Server-Block (prüfen Sie, welcher default_server besitzt), oder das an -w übergebene Verzeichnis ist nicht dasjenige, das nginx ausliefert. Legen Sie eine Datei unter /var/www/example.com/.well-known/acme-challenge/test ab und rufen Sie diese extern ab; wenn dabei ein 404-Fehler auftritt, war das Zertifikat nie das Problem.
DNS problem: NXDOMAIN looking up A for example.com, der Name löst sich öffentlich nicht auf. Dies betrifft neue Einträge, die noch nicht propagiert wurden, oder einen Eintrag in einer Zone, die Ihr Registrar nicht bedient.
too many certificates already issued for: example.com, ein Rate-Limit, auf das Nutzer beim Debuggen in einer Schleife stoßen. Let's Encrypt begrenzt identische Zertifikate (exakt dieselbe Menge an Namen) auf fünf pro Woche und erlaubt separat 50 neue Zertifikate pro registrierter Domain pro Woche; nichts hebt diese Sperre auf außer Zeit. Debuggen Sie gegen die Staging-Umgebung mit --dry-run.
nginx: [emerg] cannot load certificate "/etc/letsencrypt/live/example.com/fullchain.pem": No such file or directory, nginx ist für ein Zertifikat konfiguriert, das nie ausgestellt wurde oder mit certbot delete entfernt wurde. Kommentieren Sie den TLS-Server-Block aus, starten Sie nginx, stellen Sie das Zertifikat aus und stellen Sie den Block wieder her.
open() "/etc/letsencrypt/options-ssl-nginx.conf" failed, diese Datei wird mit dem nginx-Plugin-Paket geliefert. Auf einem certonly-System ohne python3-certbot-nginx fügen Sie entweder das Plugin hinzu oder ersetzen die Zeile include durch Ihre eigenen ssl_protocols- und ssl_ciphers-Einstellungen.
Skalierung der Zertifikatsverwaltung
Ein Zertifikat kann bis zu 100 Namen enthalten, und ein einzelnes certbot --nginx -d a.example.com -d b.example.com ... ist verlockend, bis ein veralteter DNS-Eintrag die Validierung fehlschlagen lässt und damit alle anderen Namen auf diesem Zertifikat ebenfalls deaktiviert. Separate Zertifikate pro Website fallen unabhängig voneinander aus, was bei einem Server mit mehr als nur ein paar Diensten das gewünschte Verhalten ist. Ab einer Handvoll Websites macht sich ein ACME-fähiger Reverse Proxy bezahlt: Ein mit Docker Compose betriebener Traefik Reverse Proxy für mehrere Anwendungen fordert die Zertifikate selbst an und erneuert sie, wodurch Certbot vollständig entfällt. Welcher Proxy an dieser Stelle eingesetzt wird, ist eine individuelle Entscheidung, und der Vergleich von Nginx, Caddy und Traefik hängt meist davon ab, wie viel Arbeit bei der Zertifikats- und Anwendungsverwaltung der Proxy für Sie übernehmen soll.
Sichern Sie /etc/letsencrypt vollständig, inklusive sudo tar -czf letsencrypt-$(date +%F).tar.gz -C /etc letsencrypt und unter Beibehaltung der Symlinks. Dieser Verzeichnisbaum enthält accounts/, Ihren ACME-Account-Key, den Sie nicht identisch neu generieren können. Der Umzug auf einen neuen VPS reduziert sich damit auf: Synchronisieren Sie den Baum mit -a, installieren Sie Certbot, passen Sie die DNS-Einträge an und führen Sie certbot renew --dry-run aus, bevor Sie die Dienste umstellen.
Wenn Sie den Server neu aufsetzen oder auf eine neue LTS-Version wechseln, wird der Erneuerungs-Timer nicht automatisch übernommen. Führen Sie nach jeder Migration, nach dem Einspielen eines Snapshots oder einem Distro-Upgrade systemctl list-timers 'certbot*' und einmal --dry-run aus. Wer dies versäumt, riskiert, dass eine Website 89 Tage später um 3 Uhr morgens ausfällt, weil ein Zertifikat abgelaufen ist, von dem alle annahmen, es würde sich selbst erneuern.
All dies setzt einen Server voraus, den Sie kontrollieren, mit einer öffentlichen IP-Adresse und einem für die Welt offenen Port 80 – kurz gesagt, einen VPS. Die beschriebenen Mechanismen sind auf allen diesen Systemen identisch.
Die gleichen Schritte für Zertifikate gelten für Apache statt Nginx, und wenn ein öffentliches Zertifikat keine Option ist, deckt ein selbstsigniertes Zertifikat unter Ubuntu interne Dienste ab.
FAQ
Muss Port 80 offen sein, wenn meine Website nur HTTPS ausliefert?
Ja, für den HTTP-01-Challenge-Prozess. Let's Encrypt beginnt die Validierungsanfrage immer auf Port 80. Da Certbot keine TLS-ALPN-01-Implementierung besitzt, blockiert eine Firewall, die nur Port 443 öffnet, sowohl die erste Ausstellung als auch jede nachfolgende automatische Erneuerung. Eine Weiterleitung von Port 80 auf HTTPS ist unproblematisch, da die Validierung diesem Redirect folgt. Die einzige Möglichkeit, Port 80 vollständig zu umgehen, ist die DNS-01-Challenge mit einem Provider-Plugin.
apt oder snap: Welches Certbot sollte ich für nginx unter Ubuntu 24.04 installieren?
Verwenden Sie apt. sudo apt install certbot python3-certbot-nginx liefert Ihnen Certbot 2.9.0 unter Ubuntu 24.04. Diese Version ist aktuell genug für alle Schritte in diesem Leitfaden, erhält Sicherheits-Patches über unattended-upgrades und erfordert kein snapd. Wählen Sie die snap-Variante nur, wenn Sie zwingend die allerneueste Version benötigen oder ein DNS-Plugin verwenden müssen, das ausschließlich als snap verteilt wird. Entscheiden Sie sich in jedem Fall für genau eine Methode: Zwei Installationen bedeuten zwei Erneuerungs-Timer, die auf denselben /etc/letsencrypt-Baum zugreifen. Die vergessene Installation führt dann unweigerlich zu Problemen.
Kann Certbot ein Wildcard-Zertifikat für nginx ausstellen?
Nur über DNS-01. Ein Wildcard-Zertifikat wie *.example.com hat keinen einzelnen Hostnamen, von dem eine Challenge-Datei abgerufen werden könnte. Daher funktionieren --nginx, --webroot und --standalone hier nicht. Installieren Sie das Plugin für Ihren DNS-Provider, legen Sie ein eingeschränktes API-Token in einer Datei mit Root-Rechten ab und führen Sie certbot certonly --dns-cloudflare -d example.com -d '*.example.com' aus. Setzen Sie das Wildcard-Zertifikat dabei in Anführungszeichen, damit die Shell es nicht als Globbing-Muster interpretiert.
Warum liefert nginx nach einer erfolgreichen Erneuerung immer noch das alte Zertifikat aus?
nginx hält das Zertifikat im Arbeitsspeicher und bemerkt die neue Datei auf der Festplatte erst nach einem Reload. certbot --nginx führt diesen Reload automatisch aus, aber --webroot und --standalone tun dies nicht. Eine Erneuerung kann also erfolgreich sein, während der Browser weiterhin ein ablaufendes Zertifikat anzeigt. Legen Sie ein ausführbares Skript in /etc/letsencrypt/renewal-hooks/deploy/ ab, das nginx -t && systemctl reload nginx ausführt; dieses wird dann nach jeder erfolgreichen Erneuerung gestartet.
Beweist certbot renew --dry-run, dass die Erneuerung funktionieren wird?
Größtenteils. Es führt die echte Challenge gegen die Staging-Umgebung aus – mit derselben Firewall, demselben DNS und demselben Codepfad, jedoch ohne Rate-Limit-Beschränkungen und ohne Schreibvorgänge auf die Festplatte. Ein Erfolg bestätigt also, dass die Netzwerkkonfiguration korrekt ist. Es beweist jedoch nicht zuverlässig, dass Ihr Deploy-Hook ausgelöst wird. Testen Sie dies separat: Führen Sie das Hook-Skript manuell aus und prüfen Sie sudo grep renew_hook /etc/letsencrypt/renewal/example.com.conf.