</>CodeWithKarani

Certbot Keeps Making New Certificates Instead of Renewing: --cert-name Explained

Karani GeoffreyKarani Geoffrey6 min read

You wanted to add one subdomain to an existing certificate. You ran certbot with your usual list of -d flags, and instead of quietly extending the cert you already had, certbot went off and created a brand new one, sometimes a whole new numbered lineage sitting in a -0001 directory next to the original. Now your nginx config points at the old path, the renewal timer is confused about which one to renew, and you have spent one of your precious weekly issuances on a cert you did not mean to create.

The instinct at this point is the worst possible move: delete everything under /etc/letsencrypt and start clean. That burns yet another rate-limited issuance and throws away renewal history that was working. The real problem is not certbot misbehaving. It is that certbot identifies a certificate by a name you did not set, and you have been addressing it by its domain list instead.

A certbot certificate is a lineage identified by its --cert-name, not by its domain list. If you do not pass --cert-name, certbot may not match the existing lineage and creates a new one.

  • List what you already have first: certbot certificates. Read the Certificate Name, not just the domains.
  • To change the domains on an existing cert, target it explicitly: certbot --cert-name example.com -d example.com -d www.example.com -d new.example.com.
  • Every unintended reissuance counts against the same weekly Let's Encrypt rate limit as a real one. Do not delete and recreate to "fix" it.

The confusing behaviour, seen plainly

There is no single error string here, which is part of why it is so frustrating; certbot succeeds, it just does the wrong thing quietly. What you see is a new directory appearing:

/etc/letsencrypt/live/example.com/          <- the original lineage
/etc/letsencrypt/live/example.com-0001/     <- the surprise new one certbot just made

Or, when you narrowed the domain list, certbot asks whether you meant to reduce it, or reissues the whole thing when you expected a no-op. The common thread is that certbot's idea of "which certificate is this" did not match yours.

Why this happens: a lineage is a name, not a domain list

When certbot issues a certificate, it does not store it under the domains. It stores it under a certificate name (the lineage), which by default is derived from the first -d domain you passed the very first time, but which is a stable identifier in its own right after that. All the files, the private key, the fullchain, and the renewal config in /etc/letsencrypt/renewal/<name>.conf, hang off that name.

When you run certbot again, it has to decide whether this is a renewal or reconfiguration of an existing lineage, or a request for a new one. Without --cert-name, it tries to match based on the domain set and the first domain. If the domains you pass do not line up with an existing lineage the way certbot expects (you added a domain, reordered them, or the first -d changed), it concludes you are asking for something new and creates a fresh lineage, with the -0001 suffix to avoid clobbering the old one.

So the mental model to drop is "the certificate for these domains." The correct model is "the lineage named X, which currently happens to cover these domains, and whose domain list I can change while keeping the same name and the same renewal config."

By domain list (no --cert-name) certbot -d example.com -d new.example.com domains do not match, so... new lineage: example.com-0001 By --cert-name certbot --cert-name example.com -d example.com -d new... targets the named lineage same lineage, domains updated
The domain list is the payload. The certificate name is the address. Pass the address and certbot edits in place.

The fix, in order

Step 1: list what you actually have

Before issuing anything, ask certbot what lineages exist. This is the command that prevents almost every mistake here:

certbot certificates

You will get one block per lineage. Read the Certificate Name line, which is the value you pass to --cert-name, alongside the domains it currently covers and its expiry:

Found the following certs:
  Certificate Name: example.com
    Serial Number: ...
    Domains: example.com www.example.com
    Expiry Date: 2026-09-14 ... (VALID: 52 days)
    Certificate Path: /etc/letsencrypt/live/example.com/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/example.com/privkey.pem

Now you know the exact name to target and whether the cert is even close to expiry (often it is not, and you did not need to touch it at all).

Step 2: change domains by targeting the name

To add or remove a domain on an existing lineage, pass --cert-name and the complete new domain list. The list you give replaces the lineage's domains; it is not additive, so include the ones you are keeping:

certbot --cert-name example.com \
  -d example.com \
  -d www.example.com \
  -d new.example.com

Because you named the lineage, certbot updates it in place: same certificate name, same renewal config, same paths your nginx already points at. No -0001 directory, no orphaned lineage.

Step 3: understand --allow-subset-of-names before you use it

--allow-subset-of-names tells certbot to still issue a certificate even if some of the requested domains fail their authorization challenge, issuing for the subset that validated. It is genuinely useful when one domain in a large list has broken DNS and you would rather get a cert for the rest than fail entirely.

The trap is that it changes what counts as "the same certificate." If a domain that failed to validate gets silently dropped, the issued cert now covers a different set of names than the lineage did before, which can itself trigger what looks like an unexpected reissuance or a shrunken cert you did not intend. Use it deliberately, on a specific run, when you have a domain you know is temporarily unvalidatable. Do not leave it in your standing renewal configuration, where it can quietly drop domains from your certificate the first time one has a DNS hiccup.

What people get wrong: delete and start over

The single most damaging piece of advice for this problem is "just rm -rf /etc/letsencrypt and run certbot fresh." It appears to work, and it makes everything worse in two ways. First, a fresh issuance for domains you already hold a valid certificate for counts fully against the Let's Encrypt duplicate-certificate rate limit, so if you have been experimenting, deleting and reissuing is exactly how you hit the "too many certificates already issued" wall and lock yourself out for a week. Second, you throw away the renewal configuration that was working, and often end up with the same duplicate-lineage confusion you started with, because you still are not passing --cert-name.

The correct fix for a lineage that genuinely exists twice is to delete only the unwanted lineage by name, not the whole tree:

certbot delete --cert-name example.com-0001

That removes just the surprise duplicate and leaves the original lineage and its renewal config intact.

Verification

After making a change, confirm the lineage looks the way you intended, with the right name and the full domain set on a single cert:

certbot certificates

Check that there is exactly one block for your site, that its Domains line lists every hostname you expect, and that the Certificate Path matches what your nginx or Apache config actually references. Then confirm renewal will work without surprises using a dry run against the staging environment, which does not consume any rate limit:

certbot renew --dry-run

A clean dry run that names your lineage and reports success means the renewal config is coherent. If you have been bitten by silent renewal problems before, pair this with the approach in alerting before the certificate actually expires, and make staging your default while experimenting as covered in defaulting your cert automation to Let's Encrypt staging.

When it is still broken

If certbot still creates a new lineage even with --cert-name, check that the name you passed exactly matches a Certificate Name from certbot certificates; a typo makes certbot treat it as a request to create a lineage under that new name. If nginx serves the old certificate after a successful reissue, you updated the lineage but did not reload the web server, so run systemctl reload nginx and confirm the served cert with echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates. And if you find several stray -0001, -0002 lineages from past experiments, list them all with certbot certificates and remove each unwanted one individually with certbot delete --cert-name, rather than clearing the directory by hand, so the renewal configs stay consistent.

Frequently asked questions

Why does certbot create a new certificate instead of updating the existing one?
Certbot identifies a certificate by its lineage name, not by its domain list. If you run certbot without --cert-name and the domains you pass do not line up with an existing lineage the way certbot expects, it decides you want a new certificate and creates a fresh lineage, usually in a directory with a -0001 suffix. Passing --cert-name targets the existing lineage so it updates in place.
How do I add a domain to an existing certbot certificate?
Run certbot certificates to find the Certificate Name, then run certbot with --cert-name set to that name and the complete new domain list, for example certbot --cert-name example.com -d example.com -d www.example.com -d new.example.com. The domain list replaces the lineage's domains rather than adding to them, so include every domain you want to keep.
What does --allow-subset-of-names actually do?
It tells certbot to still issue a certificate even if some requested domains fail their authorization challenge, issuing only for the domains that validated. It is useful for a one-off run when one domain has temporarily broken DNS, but it can silently drop domains and shrink your certificate, so do not leave it in your standing renewal configuration.
Should I delete /etc/letsencrypt and start over to fix a duplicate certificate?
No. Reissuing certificates you already hold counts against the Let's Encrypt weekly duplicate-certificate rate limit and can lock you out, and you lose working renewal history. To remove only an unwanted duplicate lineage, run certbot delete --cert-name example.com-0001, which leaves the original lineage and its renewal config intact.
#Certbot#Let's Encrypt#TLS#Nginx#Certificates
Keep reading

Related articles