While doing my bi-monthly certificate renewal process, I found that one of two renewals failed:
An unexpected error occurred:
requests.exceptions.ReadTimeout: HTTPSConnectionPool(host='acme-v02.api.letsencrypt.org', port=443): Read timed out. (read timeout=45)
Which, fine, things can happen during busy hours and the likes. But I tried again, and it failed again. Fine, I will it sit for a few hours before retrying. 3 hours later, failed. Odd. Sit idle a few more hours, came back and now I cannot even request a new certificate:
An unexpected error occurred:
too many certificates (5) already issued for this exact set of identifiers in the last 168h0m0s, retry after 2025-07-04 20:14:43 UTC: see Rate Limits - Let's Encrypt
I understand limits have to be put in place, but not only I disagree with these limits being enforced, I disagree with how many times I actually ran certbot to reach such limits.
It is not that I had 5 certificates issued for the exact set of identifiers and decided to request new ones: they failed to be issued, so I have zero certificates issued, yet the counter hit 5 somehow. That is a bug, either at the certbot or at the LE rate limiting process.
Then, the second bit is with certbot: Unless it is, behind the scenes, requesting a certificate twice automatically, I ran it a total of four times for this certificate, with the last being the time I got the limit reached message. Or the rate limit does not consider an RSA and EC certificates as "exact", which even so increases the request count only by one, and still short of 5.
Below is the command line I use on my dirty shell script to request manual issued certificates:
DNS_HOOK=" --dns-rfc2136
--dns-rfc2136-credentials ${WORKDIR}/dns-creds.ini
--dns-rfc2136-propagation-seconds 180"${CERTBOT_DIR}/bin/certbot certonly
--verbose
--agree-tos
-m ${EMAIL}
--preferred-chain "ISRG Root X1"
--force-renewal
--preferred-challenges dns
${DNS_HOOK}
--csr ${WORKDIR}/${DOMAIN}.ec.csr
Finally, as per Rate Limits page,
When testing or troubleshooting your applications, we recommend configuring your client to use our staging environment,
But guess what, everything works against the staging environment. I run both requests first against staging to ensure certbot updates were successful and no Internet errors exists before placing production requests:
${CERTBOT_DIR}/bin/certbot certonly
--dry-run
--test-cert
--register
--agree-tos
-m ${EMAIL}
--preferred-chain "ISRG Root X1"
--force-renewal
--preferred-challenges dns
${DNS_HOOK}
--csr ${WORKDIR}/${DOMAIN}.ec.csr
if [ $? -ne 0 ]; then
if [ x"${FRESH}" != "x" ]; then
rm -f ${WORKDIR}/${DOMAIN}.ec.key
fi
echo "Error during dry run, please verify and correct before continuing"
exit 1
fi
All that said, and while I have plenty time to resolve this, I feel it is worth for LE to review how errors are treated: not every error is at the end user' side.