I am very new to all of this, so please bear with me.
I have a docker compose setup with 2 backend services and a haproxy.
The proxy uses the (experimental) ACME integration with letsencrypt.
The DNS is handled by a dynamic DNS setup (noip).
It all seems to work well, a certificate is requested and obtained. See logs here:
Thank you @lukastribus, that got me one step further. However, I am still getting an SSL error and browser warning. The HA Proxy log shows this error:
in/2: SSL handshake failure (error:0A000412:SSL routines::ssl/tls alert bad certificate)
However, I also see some problem with cert issuance:
acme: mpin.ddns.net.pem: invalid HTTP status code 429 when getting newOrder URL: "too many certificates (5) already issued for this exact set of identifiers in the last 168h0m0s, retry after 2026-06-29 19:17:50 UTC: see Rate Limits - Let's Encrypt" (urn:ietf:params:acme:error:rateLimited), retrying in 119966s (1/5 retries)...
Hey @lukastribus, thanks for the info once more. You are correct that this is a DynDNS setup, but I’m going to try it as is because my assumption is, that the IP address is relatively static.
NoIP apparently offers a plan whereby one can bind a TLD to a dynamic IP, but all of that would cost more than this is worth.
Okay, this is starting to get in the way of things in a serious way.
I added a CNAME to a TLD under a subdomain: gis.mais-parque-industrial-nao.pt, which points to my DDNS mpin.ddns.net. I am still working on the configuration, so I have to restart the whole setup frequently.
After a few restarts, letsencrypt started whining about too many requests again. The result is that I am effectively locked out again until tomorrow. Every single fricken time I am loosing a complete day with this. It is becoming a highly infuriating affair.
We are on a clock fighting a political issue that can not wait. I can not afford being sabotaged by this stuff all the time. This stuff is becoming a serious stumbling stone for our entire group.
What else can I do to finally remove this problem?
The built-in ACME client is a experimental feature with some important limitations.
I will refer to the documentation here:
The current HAProxy architecture is a non-blocking model, access to the disk
is not supposed to be done after the configuration is loaded, because it
could block the event loop, blocking the traffic on the same thread. Meaning
that the certificates and keys generated from HAProxy will need to be dumped from outside HAProxy using “dump ssl cert” on the stats socket. It’s possible
to automate the dump of the certificates by using the dataplaneAPI or the
haproxy-dump-certs script provided in the admin/cli/ directory.
A tutorial is available here:
However you should avoid experimental features entirely if you are just looking for something that works without tinkering.
There are tons of stable ACME clients out there, thats probably a safer bet for your production workload.
If the IP is fairly stable, that’s a reasonable thing to try. Just keep in mind that the Let’s Encrypt rate limit won’t be fixed by the IP being stable — it’s about the hostname/certificate identifiers, so you’ll need to wait until the indicated retry time before issuance can succeed again for that name.
For testing changes, stick to the staging endpoint until you’re confident the flow works, then switch to production only once. Also make sure HAProxy is persisting the ACME/certificate storage in a Docker volume, otherwise container recreation can cause repeated issuance attempts and you’ll hit limits much faster.
Yes, this is the key part: don’t let the container “forget” its ACME state between restarts. In Docker Compose, the ACME account data/certs need to live on a persistent volume or bind mount, not only inside the container filesystem. Otherwise every rebuild/recreate can look like a fresh client asking Let’s Encrypt again.
Also, while debugging, use Let’s Encrypt staging or even temporarily disable automatic issuance until the routing and challenge path are confirmed. Once HTTP-01 validation works reliably and the storage survives restarts, switch back to production and request the real cert once.