Our Let’s Encrypt certificate expired and is not being renewed despite fly certs showing status “Ready” and claiming it will auto-renew. The app is now down.
Important context
Certificate was first added in June 2025
The most recent certificate was valid from October 2025
This means auto-renewal worked successfully before — unclear why it’s failing now
Certificate was due to expire, status showed “Ready” with message: “Your DNS is correctly configured and this certificate will auto-renew before expiration.”
Certificate expired at approximately 2026-01-20 12:27 UTC
App is now down due to expired certificate
We removed and re-added the hostname twice — no change
fly certs show output after re-adding shows Issued = (blank), but still claims certificate is issued:
❯ fly certs show
Status = Ready
Hostname =
DNS Provider = cloudflare
Certificate Authority = Let’s Encrypt
Issued =
Added to App = 10 minutes ago
Source = fly
✓ Your certificate has been issued!
Your DNS is correctly configured and this certificate will auto-renew before expiration.
What we tried
Ensured CNAME is correctly set as shown in setup instructions
Ran fly certs remove then fly certs add (twice)
Verified DNS settings in Cloudflare are correct (CNAME, not proxied)
DNS Configuration
Using Cloudflare with option 2 (CNAME record)
Cloud Proxy status = grey / disabled
Questions
How to get the app up again
Why didn’t the certificate auto-renew despite all green indicators?
How can we force issuance of a new certificate?
Any help appreciated — production isn’t happy anymore
We tried switching from CNAME to A/AAAA records and did another remove+add cycle — still didn’t work.
Then we added the optional ACME challenge CNAME record: CNAME _acme-challenge.xxx → xxx.flydns.net
After that, the certificate was issued successfully and the app is back up.
Still unclear why:
Auto-renewal stopped working when it had renewed fine in October
Why it did show everything is fine and would auto-renew but effectively didn’t
@khuezy Sadly I can’t take a look myself and the admin team is in another timezone. @roadmr Can I send you the details in private somehow? They asked me to redact the public domain.
Hi @Patrik1 , thanks - I can locate the app with that.
I’m fairly sure that what you saw is the typical “cloudflare dance of doom” that you have to do every 3 months or so to properly renew your fly-side certificate.
Setup with Cloudflare can be slightly tricky because there’s a race condition with the required DNS records for certificate validation - it’s not Cloudflare’s fault, or Fly’s fault, we just “fight” over which DNS record comes first and the first one that does, wins. This has, in our experience, sometimes resulted in non-renewed certificates that do renew when you click on things insistently enough, which is confusing!
When you created your Fly app, the certificate was created and validated directly using DNS-01 verification for the certificate. This certificate is valid for about 3 months.
When you enabled Cloudflare and asked it to proxy your site (Orange Cloud and Universal SSL), Cloudflare took over the externally-visible certificate for the application, also validating it using DNS-01.
The Fly-side certificate still exists, and it’s used when Cloudflare talks to your Fly app. However, since Cloudflare took over DNS-01, when Fly tries to validate the certificate when it’s about to expire, it can’t because the DNS-01 record returned by the DNS query is the one returned by Cloudflare, not the one returned by Fly.
Once the Fly certificate expires and was not validated, this is when you start getting errors because when Cloudflare tries to talk to your Fly service, its certificate is expired.
Removing and then re-adding the cert on the Fly and/or fiddling with Cloudflare’s CNAME record can sometimes get the correct Fly DNS-01 record returned which gets the certificate renewed. This is likely what happened when you started fiddling with the settings earlier today
However, it’s very likely you’ll run into the same dance in about 3 months.
To help with this, we recently added HTTP-01-based support for certificate validation behind cloudflare. Enabling it is described here, but to summarize, on Cloudflare:
Create an AAAA record only pointing to your Fly.io app’s IPv6 address.
Do not add A or CNAME records pointing to your Fly app in Cloudflare.
Enable the Cloudflare proxy (orange cloud).
Set SSL mode in Cloudflare to Full (strict).
Enable Always Use HTTPS in Cloudflare.
You don’t need to change or configure anything extra on the Fly.io side.
This way, certificate validation happens over HTTP-01 which is more reliable and not subject to the race condition.
If you do so, then two things:
Please let me know so I can verify the configuration on my side.
I’d recommend setting a reminder in about 2.75 months or so and when it fires, run fly certs show yourdomain.com --json. You should see two sets of nodes:
One for the current (maybe sometime in April) expiration date
Another one for the new certificate’s expiration date, possibly sometime in July.
If you see both sets of nodes with two distinct dates, then you’re all set. If not, please reach out so we can help and/or investigate.
Thanks for the detailed follow up! Really appreciating it.
I don’t think Cloudflare proxy was ever activated but regarding Universal SSL I don’t know. I tried to debug with letsdebug.net and both DNS-01 and HTTP-01 came up fine (before and after expiration).
Here is a JSON output from before cert expiration with only one CNAME record in place. Maybe this sheds some insight on the status of the problematic cert? Because you mentioned a set of two nodes with distinct dates, which is the case here despite failing.
I will ping my colleague after his vacation and will talk about switching over for HTTP-01 as you recommended and report back here. Thanks again for this. Can I reply then despite it being auto-closed?
This just shows renewal didn’t succeed - we’ll try to get the new certificate when the old one has about 3 weeks left, so you should definitely see the second one here and if it’s not there it’s because it failed.
But it doesn’t say why it failed, unfortunately - and since you’ve already renewed it, it will now show the correct data.
I don’t think you can reply to a closed thread, but if you start a new one, @-me and link to this one, I’ll have a look when your colleague is back.