Skip to content

tls: Add internal module to serve DNS for DNS-01#7675

Open
andrewbaxter wants to merge 1 commit into
caddyserver:masterfrom
andrewbaxter:dns01b
Open

tls: Add internal module to serve DNS for DNS-01#7675
andrewbaxter wants to merge 1 commit into
caddyserver:masterfrom
andrewbaxter:dns01b

Conversation

@andrewbaxter
Copy link
Copy Markdown

For #7663

This adds an internal DNS resolver so you can do DNS-01 by pointing your _acme-challenge subdomains at caddy itself.

How to use:

  1. Set up an A record (like my-acme-challenge.example.com) pointing to caddy, plus NS records for all _acme-challenge. subdomains you'll need (i.e. for *.MYDOMAIN do _acme-challenge.MYDOMAIN) pointing to the A record (my-acme-challenge.example.com).
  2. Open port 53 (TCP/UDP)
  3. Configure with
    dns internal "0.0.0.0:53" {
        mname "my-acme-challenge.example.com"
        rname "me.example.com"
    }
    

mname and rname are required for the synthetic SOA records required due to the NS zone cut.

This may still be rough, but I was (I think) careful in my reading of the interface specifications and relevant RFCs. I've tested it with LE (staging) and ZeroSSL and both worked great.

Assistance Disclosure

It's a combination of Gemini code and my own, and I reviewed the generated parts + tested everything.

@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Apr 27, 2026

CLA assistant check
All committers have signed the CLA.

@steadytao
Copy link
Copy Markdown
Member

Thanks for testing the NS-delegation path. I agree this proves the approach can work technically but I still think this is a much larger scope decision than simply built-in DNS-01 support.

This effectively makes Caddy an authoritative DNS server for delegated _acme-challenge zones. Even if intentionally narrow, that brings DNS server lifecycle, public UDP/TCP :53 exposure, SOA/NS correctness, negative-answer semantics, multiple-provider-instance behaviour and abuse/reflection considerations into core Caddy.

A few concrete things stood out from your changes:

  • Provision() starts TCP/UDP listeners inside a DNS provider module. If multiple issuers or automation policies configure dns.providers.internal, each one may try to bind the same listen_addr. This feels more like an app or shared service than a normal libdns provider to me.
  • mname and rname are described as required but I do not see validation. Empty SOA fields should fail config load.
  • Existing-name wrong-type answers currently become NXDOMAIN; DNS semantics should usually be NOERROR/NODATA with an authority SOA when the owner name exists but that RR type does not.
  • Delegated zones should probably answer apex NS as well as SOA, not only synthesize SOA.
  • The server appears to answer broadly for public DNS traffic rather than being aggressively limited to the delegated challenge zones and necessary RR types.

So my concern is not that the idea is impossible. It is that embedding even a small authoritative DNS server in core has a much larger maintenance and correctness surface than the current caddy-dns/acme-dns model. I would still lean toward this living as a separate plugin/module unless there is a legitimate decision with more thorough reasoning that Caddy core should own this DNS-serving surface.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants