Home / Alt manpages / certbot(1)

  • certbot(1)
  • User command
  • linux

Issue and Renew a Certificate with Certbot

Nothing kills a Friday afternoon like a certificate expiring in production, and Certbot exists so that never happens on your watch again. This walks through issuing a Let's Encrypt HTTPS certificate with the installed Certbot 2.9.0, running a renewal test that saves nothing, and checking exactly which files and domains Certbot manages.

Allow about 20 minutes for an existing web server, DNS that already points at this host, and a short maintenance window if you must use standalone mode. These examples use example.com and www.example.com as placeholders: replace them before running anything. You need control of the domain, inbound HTTP access on port 80 for an HTTP-01 challenge, and root privileges for the commands that read or write /etc/letsencrypt or touch a web server.

1. Check the installed Certbot

Start with read-only checks. They need no sudo, and they stop a common time-waster: copying commands meant for a different package or version:

$ command -v certbot
/usr/bin/certbot
$ certbot --version
certbot 2.9.0
$ certbot plugins

The last command lists available authenticators and installers. The local package is Debian's certbot 2.9.0-1 in this guide. Plugin availability is installation-specific, so do not assume an Apache, Nginx or DNS plugin exists just because it turns up in general documentation.

Checkpoint

Continue only when the binary is the one you intend to run and the plugin you need actually appears in the plugin list.

2. Choose how Certbot will prove domain control

For Apache or Nginx already serving the site, the matching plugin can authenticate and install the certificate in one go:

$ sudo certbot --apache -d example.com -d www.example.com
$ sudo certbot --nginx -d example.com -d www.example.com

Run only the command for your own server: these modes can edit the server configuration. Certbot's normal install and run behaviour turns on an HTTP to HTTPS redirect unless you pass --no-redirect, so inspect the proposed changes and keep a configuration backup before accepting them.

If the web server should keep running and you know its document root, use webroot mode instead. Certbot drops a temporary token below .well-known/acme-challenge/, and your server must serve that path publicly:

$ sudo certbot certonly --webroot -w /var/www/example -d example.com -d www.example.com

Here certonly obtains or renews the certificate but does not install it in Apache or Nginx. Confirm /var/www/example is the actual public webroot, not just a source directory.

Standalone mode is for a host where Certbot can listen on port 80 itself. It cannot share that port with another service, so this is a service-disrupting choice:

$ sudo systemctl stop nginx
$ sudo certbot certonly --standalone -d example.com -d www.example.com
$ sudo systemctl start nginx

Confirm the service name and have a recovery plan before you use this form. If Certbot fails, start the service again before investigating. Changing Certbot's local --http-01-port value alone does not move the public challenge port: the ACME server still connects on port 80.

3. Use staging when testing a new setup

Repeated failed attempts can hit the production CA's rate limits, so add --test-cert while testing a command, or --dry-run for an existing renewal configuration:

$ sudo certbot certonly --webroot -w /var/www/example \
    --test-cert -d example.com -d www.example.com
$ sudo certbot renew --dry-run

A staging certificate is deliberately untrusted by browsers. It is useful for checking challenge routing, but never deploy it as the site's live certificate. --dry-run only applies to certonly and renew; the local manual says it obtains a temporary test certificate without saving anything to disk, though it may still reload a web server and run pre or post hooks.

Checkpoint

Do not move to production until the challenge path is reachable from the public internet and the dry run succeeds. A successful dry run proves the renewal procedure works, not that an unrelated virtual host is configured correctly.

4. Inspect the certificate and its managed paths

After a real issuance, ask Certbot for its own view of the certificate:

$ sudo certbot certificates

The output lists the certificate name, domains, expiry date, certificate path and private key path. The first domain normally becomes the certificate name, but a name conflict can tack on a suffix such as -0001. Use the displayed certificate name rather than guessing a directory name:

$ sudo ls -l /etc/letsencrypt/live/example.com/
$ sudo openssl x509 -in /etc/letsencrypt/live/example.com/fullchain.pem \
    -noout -subject -issuer -dates -ext subjectAltName

The default configuration directory is /etc/letsencrypt. A typical live directory holds cert.pem, chain.pem, fullchain.pem and privkey.pem.

Warning

Treat the private key as secret material. Do not paste it into a ticket, commit it to source control, or loosen its permissions just to make a service start.

5. Test and automate renewal

renew checks every previously obtained certificate and attempts those close to expiry. It reuses the plugins and options recorded for each one, so it normally needs no domain or authenticator flags:

$ sudo certbot renew --dry-run
$ sudo certbot renew

Run the first command now. Run the second only when you actually intend a real renewal. A normal run may simply say a certificate is not yet due; that is a successful no-op, not a failure.

Check how this installation already schedules the command before creating a duplicate job:

$ systemctl list-timers --all | grep -i certbot
$ sudo grep -R "certbot renew" /etc/crontab /etc/cron.* 2>/dev/null

Official Certbot guidance says packages may ship a systemd timer or a cron entry. Pick one existing mechanism and check its logs. If your web server only reads certificate files at startup, add a carefully tested deploy hook to reload it after a successful renewal. A hook runs with operational privileges, so use an absolute executable path and test its reload command on its own first.

6. Recover from the usual failures

A webroot challenge failure usually means DNS, port 80, the virtual host or the .well-known path is wrong. Test the public route with a harmless file in the real webroot, then remove it once you have checked it:

$ printf '%s\n' certbot-check | sudo tee /var/www/example/.well-known/acme-challenge/certbot-check
$ curl -fsS http://example.com/.well-known/acme-challenge/certbot-check
certbot-check
$ sudo rm /var/www/example/.well-known/acme-challenge/certbot-check

That removal is deliberate: the check file is no longer needed. If standalone mode reports port 80 is busy, identify the listener with sudo ss -ltnp 'sport = :80', then either switch to webroot mode or stop the correct service with a recovery command already lined up.

Warning

To replace a mistaken certificate configuration, inspect it first with sudo certbot certificates. Do not use certbot delete casually: it removes every file tied to the named certificate. Revocation is effectively irreversible for that certificate too. Use revoke only for a genuine compromise or other confirmed reason, and back up any configuration before you edit it.

Done means

  • Version and plugin checked. The installed version and required plugin match what you intended to run.
  • Challenge reachable. The chosen challenge can be reached for every requested domain.
  • Certificate confirmed. A production certificate was issued, or an existing one was inspected with certbot certificates.
  • Dry run passed. sudo certbot renew --dry-run completed successfully.
  • Renewal automated once. An existing timer or cron entry, not a duplicate job, will run renewal.
  • Sensitive parts protected. The web server reload path is tested, and private keys and destructive commands stay protected.