Certbot für nginx auf Ubuntu 24.04 installieren
Lernen Sie die Installation via apt oder snap kennen. Vermeiden Sie Konflikte durch doppelte Timer und nutzen Sie die aktuelle Version für Let's Encrypt.
Certbot installieren: apt oder snap
Auf Ubuntu 24.04 stellt sudo apt install certbot python3-certbot-nginx ein funktionsfähiges Certbot bereit, das echte, öffentlich vertrauenswürdige Let's Encrypt-Zertifikate ausstellt. Die Dokumentation von Certbot empfiehlt die Nutzung von snap. Der Unterschied ist gering: Das snap-Paket folgt den Upstream-Releases, während das Archiv-Paket die Version nutzt, die mit dem LTS ausgeliefert wurde und lediglich Sicherheitsupdates erhält.
Wählen Sie eine Methode. Zwei Certbot-Installationen führen zu zwei Erneuerungs-Timern, die auf denselben /etc/letsencrypt-Baum abzielen. Die vergessene Instanz verursacht später Fehler.
Der apt-Weg:
sudo apt update
sudo apt install certbot python3-certbot-nginxDies installiert /usr/bin/certbot, das nginx-Plugin, ein certbot.service + certbot.timer-Paar und einen /etc/cron.d/certbot-Eintrag, der unter systemd keine Funktion ausführt.
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/certbotDas snap-Paket enthält einen eigenen Timer, snap.certbot.renew.timer. Entfernen Sie das apt-Paket, bevor Sie das snap-Paket installieren.
Beide Installationen verhalten sich danach identisch. Certbot 2.x verwendet standardmäßig ECDSA (P-256)-Schlüssel — nutzen Sie --key-type rsa nur für Clients, die kein ECDSA unterstützen. Alle Zustände werden unter /etc/letsencrypt gespeichert: archive/ enthält die echten Schlüssel- und Zertifikatsdateien, live/ enthält Symlinks 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 Callback. Sie fordern bei Let's Encrypt ein Zertifikat für example.com an; der Dienst löst den Namen im öffentlichen DNS auf, stellt eine Verbindung zu Port 80 an die gefundene Adresse her und fordert http://example.com/.well-known/acme-challenge/<token> an. Ihr Server antwortet mit dem exakten Token-Inhalt, den Certbot soeben auf die Festplatte geschrieben hat. Das ist der gesamte Mechanismus. Daraus ergeben sich drei Konsequenzen, die für die meisten fehlgeschlagenen Ausstellungen 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 VPS-Konsolen-Firewall, die nur Port 443 öffnet, verhindert die Ausstellung und jede zukünftige Erneuerung. - DNS muss bereits auf diesen Host zeigen. Der Validierungsserver führt eine eigene Abfrage von außen durch; Ihre
/etc/hosts-Einträge und der Browser-Cache sind für ihn irrelevant. - Wenn Sie einen AAAA-Record veröffentlichen, wird IPv6 zuerst versucht. Let's Encrypt versucht es erneut über IPv4, wenn die IPv6-Verbindung vollständig fehlschlägt — aber ein veralteter AAAA-Record, der auf einen Host zeigt, der die Verbindung annimmt und etwas anderes ausliefert, führt zu einem fatalen Fehler.
Redirects sind zulässig: Die Validierung folgt einem HTTP-Redirect zu HTTPS und ignoriert, dass das Zertifikat am Zielort fehlt, abgelaufen oder selbstsigniert ist. Was nicht möglich ist, ist der Start an einem anderen Port als Port 80. Certbot verfügt über keine TLS-ALPN-01-Implementierung, daher ist "nutzen Sie einfach 443" keine Ausweichmöglichkeit.
Auswahl eines Authentifizators: --nginx, --webroot, --standalone
--nginx ist die richtige Standardoption, wenn nginx bereits läuft und die Domain bereits ausliefert. Certbot analysiert Ihre Konfiguration, fügt einen temporären Challenge-Pfad ein, lädt nginx neu, validiert die Domain und schreibt die TLS-Direktiven in Ihren Server-Block. Es entsteht keine Downtime.
sudo certbot --nginx -d example.com -d www.example.comSkriptgesteuert für ein neues 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 nicht in Ihre nginx-Konfiguration eingreifen soll – zum Beispiel, wenn Sie die Konfiguration aus einer Vorlage generieren, in git speichern oder mit Ansible verteilen. Certbot schreibt die Challenge-Datei lediglich in ein Verzeichnis, das Sie bereits bereitstellen.
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 auf Port 80 kein Dienst lauscht: ein Mailserver, eine API, die nur über Port 443 kommuniziert, oder ein Skript beim ersten Systemstart, das vor der Installation von nginx ausgeführt wird. Certbot belegt Port 80 selbst für einige Sekunden. Wenn nginx läuft, schlägt dies fehl – stoppen Sie den Dienst 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. Daher erfolgt das Stoppen und Starten bei der automatischen Erneuerung unattended.
Ein Server-Block, der vor und nach der Zertifikatserstellung funktioniert
Das Hühnchen-Ei-Problem: nginx startet nicht, wenn ssl_certificate auf eine nicht existierende Datei verweist. Certbot kann die Validierung nicht durchführen, während nginx offline ist. Starten Sie die Website zuerst auf Port 80.
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, bestätigen Sie die Antworten von curl -I http://example.com/ von einem externen System aus und stellen Sie das Zertifikat dann aus. 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;
}
}Der Präfix ^~ im ACME-Location-Block ist entscheidend: Er verhindert, dass der return 301-Block die Challenge-Anfrage verschluckt. Wenn dieser Location auf Port 80 bleibt, funktionieren die Erneuerungen weiterhin, sobald die restliche Website nur noch über HTTPS erreichbar ist.
Die HTTP/2-Syntax hängt von Ihrer nginx-Version ab. Die Verwendung beider Formate führt zu einem Startfehler. Ubuntu 24.04 nutzt nginx 1.24, welches die Inline-Schreibweise benötigt — listen 443 ssl http2;. Debian 13 nutzt eine neuere nginx-Version, die die separate http2 on;-Direktive benötigt. Prüfen Sie zuerst nginx -v.
Verweisen Sie nginx auf live/, niemals auf archive/. Die live/-Symlinks werden bei jeder Erneuerung neu gesetzt; ein fester Pfad nach archive/ führt dazu, dass Sie an ein ablaufendes Zertifikat gebunden sind.
Wildcards bedeuten DNS-01, und DNS-01 bedeutet ein Plugin
Ein Wildcard-Zertifikat (*.example.com) kann nicht über HTTP-01 validiert werden — es gibt keinen einzelnen Hostnamen, um eine Datei abzurufen. DNS-01 ist der einzige Weg: Sie beweisen die Kontrolle durch das Veröffentlichen eines _acme-challenge.example.com TXT-Records. Certbot benötigt API-Zugangsdaten Ihres DNS-Anbieters, um dies automatisiert durchzuführen; wofür die Anbieter-Plugins existieren. Die vollständige Anleitung für Wildcard-Zertifikate behandelt die Funktionsweise des TXT-Records und die Erneuerungsfalle im manuellen Modus; die kurze Cloudflare-Version folgt danach.
sudo snap set certbot trust-plugin-with-root=ok
sudo snap install certbot-dns-cloudflareAuf dem apt-Pfad ist dies sudo apt install python3-certbot-dns-cloudflare. Die Zugangsdaten werden in einer Datei gespeichert, die nur für root zugänglich ist:
# /root/.secrets/cloudflare.ini
# then: sudo chmod 600 /root/.secrets/cloudflare.ini
dns_cloudflare_api_token = your_scoped_token_hereBeschränken Sie den Token auf DNS-Edit-Rechte für diese eine Zone. Er ist ein Schlüssel zu Ihrem DNS; behandeln Sie ihn wie einen solchen.
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
-d example.com -d '*.example.com'Setzen Sie das Wildcard in Anführungszeichen, damit die Shell es nicht als Glob verwendet. DNS-01 löst zudem Probleme, die HTTP-01 nicht lösen kann: Zertifikate für Hosts ohne öffentlichen Port 80 — ein interner Dienst, ein Server, der nur über einen selbst gehosteten WireGuard VPN auf einem VPS erreichbar ist, oder ein Admin-Panel auf einem privaten Interface.
Erneuerung: die 90 Tage, der Timer, der Deploy-Hook
Let's Encrypt Zertifikate sind 90 Tage lang gültig. Certbot führt eine Erneuerung durch, wenn weniger als 30 Tage verbleiben. Dies bietet ein 30-tägiges Zeitfenster, in dem eine fehlgeschlagene Erneuerung ein behebbares Problem darstellt und nicht zu einem Ausfall führt. Let's Encrypt versendet keine E-Mails mehr zur Ablaufwarnung. Da keine automatischen Benachrichtigungen erfolgen, liegt die Überwachung in Ihrer Verantwortung.
Prüfen Sie den Timer Ihrer Installation:
systemctl list-timers 'certbot*' 'snap.certbot*'
sudo certbot certificatescertbot renew prüft jede Konfiguration in /etc/letsencrypt/renewal/, überspringt alles außerhalb des 30-Tage-Fensters und erneuert den Rest mit exakt den Flags des ursprünglichen Durchlaufs. Daher ist der erste Durchlauf entscheidend: Hierbei werden die Einstellungen aufgezeichnet.
Das Erneuern der Datei auf der Festplatte allein bewirkt keine Änderung – nginx liefert das alte Zertifikat weiterhin aus dem Speicher aus, bis ein Reload erfolgt. Hinterlegen Sie einmalig einen Deploy-Hook:
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.shJede ausführbare Datei in renewal-hooks/deploy/ wird nach einer erfolgreichen Erneuerung ausgeführt. Das Flag --deploy-hook erfüllt dieselbe Aufgabe für ein einzelnes Zertifikat, indem es renew_hook = ... in der Erneuerungskonfiguration speichert. certbot --nginx führt den Reload automatisch aus; die Setups --webroot und --standalone tun dies nicht. Ein fehlender Hook ist der Grund, warum eine Website ein abgelaufenes Zertifikat ausliefert, während certbot certificates erfolgreich ein neues Zertifikat meldet. Jede andere Anwendung, die das Zertifikat beim Start ausliest, benötigt denselben Hook – eine containerisierte Anwendung wie eine Nextcloud VPS-Installation mit Docker, TLS und Backups benötigt hier ebenfalls einen eigenen Neustart oder Reload-Schritt.
Test der Erneuerung unter Realbedingungen
sudo certbot renew --dry-runDies führt die vollständige Challenge gegen die Staging-Umgebung von Let's Encrypt aus: derselbe Code-Pfad, dieselbe Firewall, derselbe DNS, keine Rate-Limits und keine Schreibvorgänge auf der Festplatte. Wenn der Test heute erfolgreich ist, wird auch die automatische Erneuerung in 60 Tagen erfolgreich sein, sofern sich an der Konfiguration des Systems nichts ändert.
Ein Dry Run beweist nicht, dass Ihr Reload-Hook ausgeführt wird – das Verhalten variiert je nach Certbot-Version. 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, da nginx den Port 80 bereits belegt. Verwenden Sie --nginx oder --webroot oder stoppen Sie nginx während des Vorgangs. Prüfen Sie den Prozess mit sudo ss -lntp | grep ':80'.
Timeout during connect (likely firewall problem) — Let's Encrypt konnte den Port 80 nicht erreichen. Prüfen Sie die Verbindung schrittweise: sudo ufw status (öffnen Sie diesen mit sudo ufw allow 'Nginx Full'), dann die Firewall des VPS-Anbieters und schließlich DNS. Testen Sie von einem System außerhalb Ihres Servers: curl -sSv http://example.com/.well-known/acme-challenge/test. Ein veralteter AAAA-Record verursacht 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 landet in einem anderen Server Block (prüfen Sie, welcher default_server besitzt) oder das an -w übergebene Verzeichnis ist nicht das Verzeichnis, das nginx bedient. Platzieren Sie eine Datei unter /var/www/example.com/.well-known/acme-challenge/test und rufen Sie diese extern auf; wenn ein 404-Fehler erscheint, liegt das Problem nicht am Zertifikat.
DNS problem: NXDOMAIN looking up A for example.com — der Name lässt sich öffentlich nicht auflösen. Dies geschieht durch neue Records, die noch nicht propagiert wurden, oder durch einen Record in einer Zone, die Ihr Registrar nicht bedient.
too many certificates already issued for: example.com — ein Rate Limit, das häufig bei der Fehlersuche in Schleifen auftritt. Let's Encrypt begrenzt Duplikate von Zertifikaten — exakt dieselbe Menge an Namen — auf fünf pro Woche. Zusätzlich sind 50 neue Zertifikate pro registrierter Domain pro Woche erlaubt; nur Zeit behebt diese Sperre. Nutzen Sie --dry-run für das Debugging im Staging-Modus.
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 ausgeliefert. Fügen Sie auf einem certonly System ohne python3-certbot-nginx entweder das Plugin hinzu oder ersetzen Sie die include Zeile durch Ihre eigenen ssl_protocols und ssl_ciphers Einstellungen.
Verwaltung im großen Maßstab
Ein Zertifikat kann bis zu 100 Namen enthalten. Ein einzelnes certbot --nginx -d a.example.com -d b.example.com ... ist verlockend, bis ein veralteter DNS-Eintrag die Validierung fehlschlägt und alle anderen Namen auf diesem Zertifikat mit in den Abgrund reißt. Separate Zertifikate pro Website schlagen unabhängig voneinander fehl. Das ist das gewünschte Verhalten bei einem Server, der mehr als ein paar Dienste hostet. Ab einer Handvoll Websites lohnt sich ein ACME-fähiger Reverse Proxy: Ein Traefik reverse proxy running multiple apps under Docker Compose fordert Zertifikate selbstständig an und erneuert sie; Certbot wird dabei nicht mehr benötigt.
Sichern Sie /etc/letsencrypt vollständig — sudo tar -czf letsencrypt-$(date +%F).tar.gz -C /etc letsencrypt — inklusive der Symlinks. Dieser Verzeichnisbaum enthält accounts/, Ihren ACME-Account-Key, der nicht identisch regeneriert werden kann. Ein Umzug auf einen neuen VPS reduziert sich dann auf: Den Baum mit -a per rsync übertragen, Certbot installieren, DNS umstellen und certbot renew --dry-run vor der Umschaltung ausführen.
Wenn Sie den Server neu aufsetzen oder auf ein neues LTS wechseln, wird der Erneuerungs-Timer nicht mit übertragen. Führen Sie nach jeder Migration, jeder Snapshot-Wiederherstellung oder jedem Distro-Upgrade systemctl list-timers 'certbot*' und --dry-run aus. Das Auslassen dieser Schritte führt dazu, dass eine Website 89 Tage später um 3 Uhr morgens offline geht, weil das Zertifikat, von dem man eine automatische Erneuerung annahm, nicht erneuert wurde.
All dies setzt eine Maschine voraus, die Sie kontrollieren, mit einer öffentlichen IP und dem offenen Port 80 — also einen VPS. Die oben genannten Mechanismen sind auf allen solchen Systemen identisch.
Die gleichen Schritte für Zertifikate gelten für Apache statt nginx. Wenn ein öffentliches Zertifikat keine Option ist, deckt ein selbstsigniertes Zertifikat auf Ubuntu interne Dienste ab.
FAQ
Muss Port 80 offen sein, wenn meine Website nur HTTPS nutzt?
Ja, für die HTTP-01 Challenge. Let's Encrypt startet die Validierungsanfrage immer über 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 automatische Erneuerung. Eine Weiterleitung von Port 80 auf HTTPS ist zulässig — die Validierung folgt der Weiterleitung. Die einzige Möglichkeit, Port 80 vollständig zu umgehen, ist die DNS-01 Methode mittels eines Provider-Plugins.
apt oder snap — welches Certbot soll ich für nginx auf Ubuntu 24.04 installieren?
Verwenden Sie apt. sudo apt install certbot python3-certbot-nginx liefert Certbot 2.9.0 auf Ubuntu 24.04. Diese Version ist für alle Inhalte dieses Leitfadens aktuell genug, erhält Sicherheitsupdates über unattended-upgrades und benötigt kein snapd. Wählen Sie snap nur, wenn Sie sofort die neueste Version benötigen oder ein DNS-Plugin, das exklusiv als snap verteilt wird. Wählen Sie in jedem Fall genau eine Methode: Zwei Installationen führen zu zwei Renewal-Timern, die auf denselben /etc/letsencrypt Baum zeigen, und die vergessene Installation verursacht Fehler.
Kann Certbot ein Wildcard-Zertifikat für nginx ausstellen?
Nur über DNS-01. Ein Wildcard wie *.example.com hat keinen einzelnen Hostnamen, um eine Challenge-Datei abzurufen. Daher sind --nginx, --webroot und --standalone nicht möglich. Installieren Sie das Plugin für Ihren DNS-Provider, hinterlegen Sie einen eingeschränkten API-Token in einer Datei mit Root-Rechten und führen Sie certbot certonly --dns-cloudflare -d example.com -d '*.example.com' aus, wobei Sie das Wildcard in Anführungszeichen setzen, um Shell-Globbing zu verhindern.
Warum liefert nginx nach einer erfolgreichen Erneuerung immer noch das alte Zertifikat aus?
nginx hält das Zertifikat im Arbeitsspeicher. Die neue Datei auf der Festplatte wird erst nach einem Reload erkannt. certbot --nginx führt den Reload für Sie 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; dies wird 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 — gleiche Firewall, gleiches DNS, gleicher Code-Pfad — ohne Rate-Limits und ohne Daten auf der Festplatte zu schreiben. Ein Erfolg bedeutet, dass die Netzwerk-Konfiguration korrekt ist. Es beweist jedoch nicht zuverlässig, ob Ihr Deploy-Hook funktioniert. 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.