A Discourse install or rebuild can reject a valid Let’s Encrypt certificate with:
C=US, O=Let's Encrypt, CN=YR2
error 2 at 1 depth lookup: unable to get issuer certificate
error fullchain.cer: verification failed
I reproduced this immediately after successful RSA issuance. The failed check triggers an unnecessary --force request, which can lead to HTTP 429 / rateLimited / “too many certificates”. In my installation, ECDSA issuance was then blocked and HTTPS did not start.
With the affected chains, each rebuild or container restart can trigger unnecessary forced reissuance of RSA and ECDSA certificates, even when they are still valid. Successful reissuances consume the Let’s Encrypt quota, so repeated rebuilds or restarts can quickly reach the rate limit.
This can go unnoticed while HTTPS continues working with certificates already installed. Deleting and reinstalling an instance with the same hostname does not reset that quota. If required certificates are missing on the new installation, rate-limited issuance can prevent HTTPS from starting.
Fix
In templates/web.letsencrypt.ssl.template.yml, inside cert_exists(), replace:
- openssl verify -CAfile <(openssl x509 -in ca.cer) fullchain.cer
+ openssl verify -untrusted ca.cer fullchain.cer
Keep the rest of the function unchanged. The corrected template must be included in the next container rebuild to update /usr/local/bin/letsencrypt.
If you are already rate-limited, the patch does not reset the quota. Apply the fix and respect the retry after time before attempting further issuance.
Confirm the chain-verification problem
From the affected certificate directory inside the container (/shared/letsencrypt/<hostname>, or <hostname>_ecc), compare:
openssl verify -CAfile <(openssl x509 -in ca.cer) fullchain.cer
openssl verify -untrusted ca.cer fullchain.cer
In the reproduced case, the first command fails with error 2; the second returns:
fullchain.cer: OK
Cause and validation
openssl x509 -in ca.cer reads only the first certificate from the issuer bundle. On the observed YR2 chain, it drops the cross-signed Root YR needed to reach ISRG Root X1.
-untrusted ca.cer supplies the complete issuer bundle while keeping trust anchors in the system store, preserving the intent of the 2021 fix (#576).
I verified actual RSA and ECDSA chains inside the container. A full rebuild with the patch reused both existing certificates: two Skip messages, both chains installed, and nginx -t passed.