How-to guide · Automate renewal

How to get and renew Let's Encrypt certificates with certbot

In one sentence

certbot gets a Let's Encrypt certificate for your Linux server, installs it, renews it automatically on the CA's schedule, and reloads your web server each time.

Task
Automate renewal
Platforms
  • Linux
  • nginx
  • Apache
Who it is for
Level
Practitioner · 7 steps
On this page
  1. Before you start
  2. Steps
  3. 1. Install certbot
  4. 2. Rehearse against the staging CA
  5. 3. Get the certificate
  6. 4. Use the right files
  7. 5. Check that renewal is automatic
  8. 6. Reload your server after each renewal
  9. 7. Optional: choose a profile
  10. Check it worked
  11. If something goes wrong
  12. Why this works
  13. Go deeper

Before you start

  • A Linux server with a public DNS name (A and, if you use IPv6, AAAA records) pointing to it, and port 80 reachable from the internet for the HTTP-01 challenge.
  • nginx or Apache already serving that name over HTTP, or nothing on port 80 at all.
  • Root access, and snapd (the installation the certbot project recommends).
  • For a wildcard name, you need the DNS-01 challenge instead: see wildcard certificates with DNS-01.

Why it matters: Let’s Encrypt certificates are valid for 90 days by default, and the default drops to 64 days from 10 February 2027. Only automatic renewal keeps up.

Steps

1. Install certbot

The certbot documentation recommends the snap, which stays current and comes with renewal set up. Remove an older distribution package first; the commands are those of certbot’s setup instructions:

sudo apt-get remove certbot            # if it was installed from the distribution
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/local/bin/certbot
certbot --version

Distribution packages can be several major versions behind; check that you have certbot 4.1 or later, which supports ARI. We ran our tests with certbot 5.8.0.

2. Rehearse against the staging CA

Let’s Encrypt’s staging environment has much higher rate limits and issues untrusted test certificates. Prove your setup there first:

sudo certbot --nginx --test-cert -d example.com -d www.example.com

When it works, delete the test certificate with sudo certbot delete --cert-name example.com and continue with step 3.

3. Get the certificate

Pick the plugin that fits your server:

# nginx: gets the certificate, edits the server block, reloads nginx
sudo certbot --nginx -d example.com -d www.example.com

# Apache: the same for Apache httpd
sudo certbot --apache -d example.com -d www.example.com

# Any web server: only gets the certificate, through files in the web root
sudo certbot certonly --webroot -w /var/www/example -d example.com -d www.example.com

--standalone runs certbot’s own temporary web server, for machines with nothing on port 80. The first -d name becomes the certificate’s name. This is the output from our test run, which used certonly --standalone against Pebble, Let’s Encrypt’s test CA (it issues short test certificates):

Account registered.
Requesting a certificate for www.example.com and example.com

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/www.example.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/www.example.com/privkey.pem
This certificate expires on 2026-10-26.
These files will be updated when the certificate renews.

We ran with a separate configuration folder; in the outputs on this page we show the default /etc/letsencrypt paths instead.

4. Use the right files

/etc/letsencrypt/live/<name>/ holds links to the current versions in ../../archive/:

cert.pem -> ../../archive/www.example.com/cert1.pem
chain.pem -> ../../archive/www.example.com/chain1.pem
fullchain.pem -> ../../archive/www.example.com/fullchain1.pem
privkey.pem -> ../../archive/www.example.com/privkey1.pem

Point your server at fullchain.pem and privkey.pem, by path, never by copying them. fullchain.pem is, in certbot’s words, “what Apache >= 2.4.8 needs for SSLCertificateFile, and what Nginx needs for ssl_certificate” (where are my certificates?). See nginx and Apache. New keys are ECDSA P-256 by default since certbot 2.0; add --key-type rsa only for clients that need RSA.

5. Check that renewal is automatic

The snap installs a systemd timer that runs certbot renew. Look for it, then rehearse a renewal against staging:

systemctl list-timers | grep certbot
sudo certbot renew --dry-run
Simulating renewal of an existing certificate for www.example.com and example.com
...
Congratulations, all simulated renewals succeeded:
  /etc/letsencrypt/live/www.example.com/fullchain.pem (success)

certbot renew renews only what is due. Since certbot 4.1 it asks the CA through ARI, RFC 9773, on the IETF standards track; for Let’s Encrypt that “will typically cause renewal at around 2/3rds of the certificate’s lifetime” (changelog). Without ARI, certbot 4.0 and later renew with a third of the lifetime left. Since certbot 5.0, the renewal file also records when certbot may ask the CA again (the ARI Retry-After). Ours:

[acme_renewal_info]
ari_retry_after = 2026-10-20T10:32:48

When certbot renew runs without a terminal, as from the timer, it first waits a random delay (ours logged 253 seconds) to spread the load on the CA.

6. Reload your server after each renewal

The nginx and Apache plugins reload the server themselves. With --webroot or --standalone, add a deploy hook, which runs only after a successful renewal (hooks):

printf '#!/bin/sh\nsystemctl reload nginx\n' | sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-nginx
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx

--dry-run skips deploy hooks unless you add --run-deploy-hooks.

7. Optional: choose a profile

certbot 4.0 and later can request an ACME profile with --preferred-profile. Let’s Encrypt offers 45-day certificates in its opt-in tlsserver profile and six-day certificates in its shortlived profile (profiles). Only choose a short profile once renewal and reloads are proven.

Check it worked

sudo certbot certificates
Found the following certs:
  Certificate Name: www.example.com
    Serial Number: 518ad8f83862ec54
    Key Type: ECDSA
    Identifiers: www.example.com example.com
    Expiry Date: 2026-10-26 02:32:46+00:00 (VALID: 5 days)
    Certificate Path: /etc/letsencrypt/live/www.example.com/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/www.example.com/privkey.pem

Then check what the server sends from outside, with openssl s_client -connect www.example.com:443 -servername www.example.com, and paste the chain into the chain checker. The lifetime calendar shows when renewals will fall:

Try it: Lifetime calendarOpen the full tool

Runs in your browser. Nothing you type or paste is sent anywhere.

Start from

The schedule for public TLS certificates

Issued fromLongest lifetimeDomain check reuseRenewals a year, at least
1 September 2020398 days398 days (from 1 October 2021)1
15 March 2026200 days200 days2
15 March 2027100 days100 days4
15 March 202947 days10 days8

From the CA/Browser Forum Baseline Requirements (sections 6.3.2 and 4.2.1), checked 20 October 2026. Renewals a year: 365 divided by the lifetime, rounded up; renewing earlier means more.

Let's Encrypt no longer sends expiration reminder emails, since 4 June 2025. Monitor expiry yourself: see how to check and monitor expiry.

If something goes wrong

  • The challenge fails. Our test with a broken DNS setup showed the typical form:

    Certbot failed to authenticate some domains (authenticator: standalone). The Certificate Authority reported these problems:
      Identifier: example.com
      Type:   connection

    Check that every name’s A and AAAA records point to this server, that port 80 is open, and that nothing intercepts /.well-known/acme-challenge/. A stale AAAA record is a common cause.

  • Rate limit errors. Let’s Encrypt allows up to 5 certificates for the exact same set of names every 7 days, up to 50 certificates per registered domain every 7 days, and up to 5 failed validations per name, per account, per hour (rate limits). Debug on staging (step 2). Renewals coordinated by ARI are exempt.

  • Clients report unable to verify the first certificate. The server uses cert.pem instead of fullchain.pem (step 4).

  • The browser still shows the old certificate, or NET::ERR_CERT_DATE_INVALID. The server was not reloaded after renewal (step 6), or the timer is missing (step 5).

  • --dry-run works, but real renewals fail. Compare /etc/letsencrypt/renewal/<name>.conf with your current setup, and read /var/log/letsencrypt/letsencrypt.log.

Why this works

certbot speaks ACME: it creates an account key, asks for a certificate, proves control of each name by answering an ACME challenge on port 80, then sends a CSR and downloads the chain. Renewal repeats the same steps with a new key. See ACME and the 47-day schedule, Proving you own the name and Inventory, expiry and renewal.

Go deeper

Early edition. Checked against the standards; an independent expert review is in progress. Found a mistake? Tell us.

Last reviewed Edition 0.9