<!-- https://pkizerotohero.com/guides/certbot-lets-encrypt/ | Markdown mirror of the HTML page | PKI Zero to Hero, by Duyutech BV -->

> Get a free Let's Encrypt certificate with certbot for nginx or Apache, test on staging, automate renewal with ARI and deploy hooks, fix failed challenges.

Source: https://pkizerotohero.com/guides/certbot-lets-encrypt/ · Last reviewed: 2026-10-20

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](https://pkizerotohero.com/guides/#task-automate)

Platforms

- Linux
- nginx
- Apache

Who it is for

- [IT ops](https://pkizerotohero.com/start/#itops)
- [Developer](https://pkizerotohero.com/start/#developer)

Level

Practitioner · 7 steps

## 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](https://pkizerotohero.com/guides/wildcard-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](https://eff-certbot.readthedocs.io/en/stable/install.html) 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](https://certbot.eff.org/instructions?ws=nginx&os=snap):

```bash
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](https://pkizerotohero.com/handbook/glossary/#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:

```bash
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:

```bash
# 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):

```text
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/`:

```text
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?](https://eff-certbot.readthedocs.io/en/stable/using.html#where-are-my-certificates)). See [nginx](https://pkizerotohero.com/guides/install-certificate-nginx/) and [Apache](https://pkizerotohero.com/guides/install-certificate-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:

```bash
systemctl list-timers | grep certbot
sudo certbot renew --dry-run
```

```text
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](https://github.com/certbot/certbot/blob/main/certbot/CHANGELOG.md)). 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:

```text
[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](https://eff-certbot.readthedocs.io/en/stable/using.html#renewing-certificates)):

```bash
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](https://letsencrypt.org/docs/profiles/)). Only choose a short profile once renewal and reloads are proven.

## Check it worked

```bash
sudo certbot certificates
```

```text
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:

*Interactive tool: Lifetime calendar (runs in the browser at [/tools/lifetime/](https://pkizerotohero.com/tools/lifetime/))*

Let's Encrypt no longer sends expiration reminder emails, since 4 June 2025. Monitor expiry yourself: see [how to check and monitor expiry](https://pkizerotohero.com/guides/check-certificate-expiry/).

## If something goes wrong

- **The challenge fails.** Our test with a broken DNS setup showed the typical form:
    
    ```text
    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](https://letsencrypt.org/docs/rate-limits/)). Debug on staging (step 2). Renewals coordinated by ARI are exempt.
    
- **Clients report [`unable to verify the first certificate`](https://pkizerotohero.com/errors/openssl-verify-error-21/).** The server uses `cert.pem` instead of `fullchain.pem` (step 4).
    
- **The browser still shows the old certificate, or [`NET::ERR_CERT_DATE_INVALID`](https://pkizerotohero.com/errors/chrome-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`.
    

Warning

Do not test on production

Repeated attempts against the production CA burn your rate limits and can lock you out of new certificates for days. Use `--test-cert` and `--dry-run` until everything passes.

## Why this works

certbot speaks [ACME](https://pkizerotohero.com/handbook/glossary/#acme): it creates an account key, asks for a certificate, proves control of each name by answering an [ACME challenge](https://pkizerotohero.com/handbook/glossary/#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](https://pkizerotohero.com/handbook/acme/), [Proving you own the name](https://pkizerotohero.com/handbook/domain-validation/) and [Inventory, expiry and renewal](https://pkizerotohero.com/handbook/certificate-lifecycle/).

## Go deeper

- [certbot user guide](https://eff-certbot.readthedocs.io/en/stable/using.html): plugins, renewal, hooks and every option.
- [Let’s Encrypt: staging environment](https://letsencrypt.org/docs/staging-environment/): its limits and test roots.
- [Let’s Encrypt: rate limits](https://letsencrypt.org/docs/rate-limits/): the current limits and exemptions.
- [Let’s Encrypt: integration guide](https://letsencrypt.org/docs/integration-guide/): renewal timing and ARI.
- [RFC 9773](https://www.rfc-editor.org/rfc/rfc9773): ACME Renewal Information.

**Early edition.** Checked against the standards; an independent expert review is in progress. Found a mistake? [Tell us](https://pkizerotohero.com/contact/?topic=content-error&page=/guides/certbot-lets-encrypt/).

Last reviewed 20 October 2026Edition 0.9

## Keep going

### Learn why it works

- [Chapter 20: ACME and the 47-day schedule](https://pkizerotohero.com/handbook/acme/)
- [Chapter 19: Inventory, expiry and renewal](https://pkizerotohero.com/handbook/certificate-lifecycle/)
- [Chapter 11: Proving you own the name: DV, OV, EV and CAA](https://pkizerotohero.com/handbook/domain-validation/)

### Error pages

- [verify error:num=21:unable to verify the first certificate](https://pkizerotohero.com/errors/openssl-verify-error-21/)
- [NET::ERR\_CERT\_DATE\_INVALID](https://pkizerotohero.com/errors/chrome-err-cert-date-invalid/)
- [SSL certificate problem: unable to get local issuer certificate](https://pkizerotohero.com/errors/curl-unable-to-get-local-issuer-certificate/)

### Tools

- [Lifetime calendar](https://pkizerotohero.com/tools/lifetime/): See how long a certificate may live on any date, and when to renew.
- [Chain checker](https://pkizerotohero.com/tools/chain/): Paste a chain and see which link is missing, expired or out of order.

### Topics

- [Lifecycle and automation](https://pkizerotohero.com/topics/lifecycle-and-automation/)

## More guides: Automate renewal

- [How to automate certificates in Kubernetes with cert-manager](https://pkizerotohero.com/guides/kubernetes-cert-manager/)
- [How to automate certificates on Windows with win-acme](https://pkizerotohero.com/guides/win-acme-windows/)
- [How to get a wildcard certificate with DNS-01](https://pkizerotohero.com/guides/wildcard-dns-01/)
