DevOps & Infrastructure

Systemd-Resolved DNS Bugs Cripple Caddy

Your Caddy certificate just expired. Don't blame Caddy. Blame your trusty systemd-resolved. It's been lying about DNS. And you probably didn't even notice.

A stylized icon representing a broken certificate, with binary code forming its edges.

Key Takeaways

  • Systemd-resolved can silently fail DNS queries, preventing Caddy's ACME renewals.
  • The issue is not with Caddy or ACME, but with systemd-resolved's deceptive behavior.
  • Workarounds include bypassing system DNS, restarting systemd-resolved, or using DNS-over-HTTPS.

The certificate’s gone. Kaput. Not just expired, but expired days ago, and nobody raised a digital eyebrow until the website started throwing browser-level tantrums. Running Caddy on a systemd-based Linux box, you figured ACME renewals were humming along. The logs, bless their heart, said nothing. Nothing at all.

Except they were. Or rather, systemd-resolved was. This charming piece of network plumbing has a peculiar habit: it lies about DNS. Not always. Not to everyone. But sometimes, under specific, maddeningly inconsistent conditions related to upstream resolvers, it just returns SERVFAIL. For certain queries. And Caddy, ever the diligent server, sees this failure and quietly aborts its certificate renewal. Poof. No new cert. Just a slow, creeping digital decay.

Here’s the kicker: your systemd-resolved status shows zilch. dig might point to 8.8.8.8 and get a perfectly reasonable answer. The problem isn’t the internet. It’s the little stub resolver in your own box, whispering sweet nothings about connectivity while actively sabotaging your applications. And it keeps its little secrets well hidden, logging nothing of consequence for your debugging pleasure.

The Unseen Saboteur

This is the kind of bug that makes you question your sanity. You check Caddy. Is Caddy broken? Nope. Is ACME broken? Nope. Is your DNS provider down? Heavens, no, everything else is working fine. It’s the silent, invisible rot that festers in the most mundane parts of your infrastructure.

The stub resolver is the one lying to your application, and it doesn’t log it anywhere useful.

That quote right there? It’s the whole damn story. It’s a perfect encapsulation of the sheer, unadulterated frustration that comes with debugging a problem that’s actively hiding from you. It’s not a loud siren; it’s a whisper in the dark.

How to Stop the Digital Decay

So, what do you do when your systemd-resolved decides to play hide-and-seek with your DNS queries? The article offers a few palliative measures. First, you can tell Caddy to just ignore the system’s DNS configuration entirely. Point it straight at Cloudflare’s 1.1.1.1 or Google’s 8.8.8.8 within your Caddyfile. Easy enough.

{
  servers :443 {
    dns resolver 1.1.1.1
  }
}

Alternatively, you can play with Go’s GODEBUG environment variable, forcing the application’s networking stack to use its own resolver instead of the system’s questionable judgment. That’s a bit more… opaque. For the less adventurous, a simple systemctl restart systemd-resolved will clear the cobwebs. But it’s a band-aid. You’ll be back here again.

Why is This Happening?

This isn’t just a Caddy problem, mind you. This is a systemd-resolved problem. A fundamental issue with how modern Linux systems handle name resolution. We’ve layered abstractions upon abstractions, and sometimes, those layers start doing their own thing. We’re so busy congratulating ourselves on sophisticated network stacks that we forget the basics. Does DNS work? Yes. Usually. And that’s the problem.

If you’re running Caddy on systemd-resolved and you’ve experienced mysterious cert expirations, the solution isn’t a deep dive into Caddy’s ACME client. It’s a blunt investigation into your local DNS resolver. It’s the kind of thing that wastes an entire afternoon, maybe more, leaving you wondering who let the digital sheep out of the pasture.

It’s a stark reminder: even the most polished open-source tools can be tripped up by the most mundane, yet critical, system components. Especially when those components are selectively lying to you.


🧬 Related Insights

Written by
Open Source Beat Editorial Team

Curated insights, explainers, and analysis from the editorial team.

Worth sharing?

Get the best Open Source stories of the week in your inbox — no noise, no spam.

Originally reported by Dev.to

Stay in the loop

The week's most important stories from Open Source Beat, delivered once a week.