Forcing certmagic to use system resolvers for propagation checks?

1. Caddy version (caddy version):

v2.5.0-rc.1 h1:d/ivzqaW+ht8J4yD+XI9omgCDIbQCDOD5AzKPTwkwWk=

2. How I run Caddy:

root@AGW-see-caddy01:/etc/caddy# /usr/local/bin/caddy-custom-latest run

a. System environment:

Devuan LXC

b. Command:

root@AGW-see-caddy01:/etc/caddy# /usr/local/bin/caddy-custom-latest run

c. Service/unit/compose file:


d. My complete Caddyfile or JSON config:

acme_dns acmedns /etc/acmedns/clientstorage.json

} {
tls {
dns acmedns /etc/acmedns/clientstorage.json

3. The problem I’m having:

Internal protected system, only have proxied access to LetsEncrypt/ZeroSSL and via HTTPS and local (firewall) DNS resolver.

CertMagic seems to ignore the resolvers and try to go straight to the source instead of the system resolvers

4. Error messages and/or full log output:

2022/04/18 20:59:13.018 INFO tls.issuance.acme waiting on internal rate limiter {“identifiers”: [“”], “ca”: “”, “account”: “”}
2022/04/18 20:59:13.018 INFO tls.issuance.acme done waiting on internal rate limiter {“identifiers”: [“”], “ca”: “”, “account”: “”}
2022/04/18 20:59:14.028 INFO tls.issuance.acme.acme_client trying to solve challenge {“identifier”: “”, “challenge_type”: “dns-01”, “ca”: “”}
2022/04/18 21:00:17.937 ERROR tls.obtain could not get certificate from issuer {“identifier”: “”, “issuer”: “”, “error”: “[] solving challenges: waiting for solver certmagic.solverWrapper to be ready: checking DNS propagation of dial tcp i/o timeout (order= (ca=”}

5. What I already tried:

added resolvers (wish is was global enforceable)

6. Links to relevant resources:

Just so I understand, you’re asking to use a different resolver for propagation checks than for resolving requests to your DNS provider?

I don’t think that’s possible right now, Caddy uses the same resolver config for both, I think.

Well, I want it to always use my system resolver, but Caddy/certMagic seems to try and be smart by doing the resolution it self and trying to do the work of the resolver and thus not querying the system resolver, but instead directly itself/

I’m confused. You configured resolvers here though:

Leave this out, and Caddy will use the system resolver by default.


No, it doesn’t.

It does the “smart thing” and try to do direct DNS.
I have the firewall logs showing that it DOES do the wrong “smart thing” , EVEN with those ( is the system resolver) and isn’t even asked.

The other part to this, I realize that should be asked: to NOT track the DNS, as querying the internal DNS, will yield a different answer from the external DNS as only the external DNS (that ACME server queries) need the CNAME/TXT records, as the internal DNS doesn’t, as it contains only the internal IPs, and nothing that’s “external”

Lets do some logs and tcpdumps to show, the Caddyfile I’ll test/use:

        acme_dns acmedns /etc/acmedns/clientstorage.json

* {
        respond "Hello SSL"

Do note The EXTERNAL DNS domain (ie. when you, and ACME/LE/ZeroSSL query you’ll get a response for is configured correctly. I am not going to change that. I’m only going to change the “internal”/protected DNS and firewall rules.

FIRST: Internal doesn’t have the configured, and * points to, so _challenge would also point to

Caddy log :
tcpdump’s port 53

the relevant portions (for me):
from DNS showing that it tries to query the _challenge, and got “nothing” (as expected, you are an internal not needing the external stuff) > [bad udp cksum 0x3d64 -> 0x68b1!] 932+ [1au] SOA? ar: . OPT UDPsize=4096 (63)
06:22:04.856588 IP (tos 0x0, ttl 64, id 61757, offset 0, flags [DF], proto UDP (17), length 174) > [udp sum ok] 932 q: SOA? 1/1/1 CNAME ns: SOA 2022041901 28800 7200 604800 600 ar: . OPT UDPsize=4096 (146)
06:22:04.856754 IP (tos 0x0, ttl 64, id 9315, offset 0, flags [DF], proto UDP (17), length 75) > [bad udp cksum 0x3d54 -> 0xcd5a!] 28823+ [1au] SOA? ar: . OPT UDPsize=4096 (47)
06:22:04.865809 IP (tos 0x0, ttl 64, id 62013, offset 0, flags [DF], proto UDP (17), length 144) > [udp sum ok] 28823 q: SOA? 0/1/1 ns: SOA 2022041901 28800 7200 604800 600 ar: . OPT UDPsize=4096 (116)

From the caddy log:

{"level":"info","ts":1650349324.3459597,"logger":"tls.issuance.acme.acme_client","msg":"trying to solve challenge","identifier":"","challenge_type":"dns-01","ca":""}
{"level":"error","ts":1650349355.0679355,"logger":"tls.issuance.acme.acme_client","msg":"cleaning up solver","identifier":"*","challenge_type":"dns-01","error":"no memory of presenting a DNS record for (probably OK if presenting failed)"}

Doesn’t matter how many times, it doesn’t seem to remember that “presenting” DNS record, which I guess is related to it “wanting” to check the record itself, not trusting the push? Is this perhaps related to the “fun” with delegating the domain to update/check ?

So Next test to show that caddy/certmagic/whomever does direct DNS and ignores the system resolver:

I added in the INTERNAL DNS CNAME to

Caddy debug output:

the interesting part:

{"level":"error","ts":1650353308.67106,"logger":"tls.obtain","msg":"could not get certificate from issuer","identifier":"*","issuer":"","error":"[*] solving challenges: waiting for solver certmagic.solverWrapper to be ready: checking DNS propagation of dial tcp i/o timeout (order= (ca="}

The tcpdump -a port 53 output:

the interesting line confirming my statements that certMagic does the DNS direct and not via the system resolver, first a UDP, and then TCP on port 53:

07:28:08.517783 IP > 15495 [1au] TXT? (82)
07:28:18.518476 IP > 22295+ AAAA? (37)
07:28:18.518537 IP > 144+ A? (37)
07:28:18.527488 IP > 144 1/0/0 A (53)
07:28:18.543452 IP > 22295 0/0/0 (37)
07:28:18.543646 IP > Flags [S], seq 3673031871, win 64240, options [mss 1460,sackOK,TS val 2349545146 ecr 0,nop,wscale 7], length 0
07:28:19.578246 IP > Flags [S], seq 3673031871, win 64240, options [mss 1460,sackOK,TS val 2349546180 ecr 0,nop,wscale 7], length 0
07:28:21.594252 IP > Flags [S], seq 3673031871, win 64240, options [mss 1460,sackOK,TS val 2349548196 ecr 0,nop,wscale 7], length 0
07:28:25.846248 IP > Flags [S], seq 3673031871, win 64240, options [mss 1460,sackOK,TS val 2349552448 ecr 0,nop,wscale 7], length 0

So the questions:

(i) If there are no resolvers line, why does certMagic/Caddy do direct DNS to the ?
(ii) how can I tell certMagic caddy to explicitly trust the http POST update, and not to check the TXT records?
(iii) how do I tell certMagic/caddy to rather wait/delay a configurable time, for the records (instead of checking) and then to proceed with the solving requests?

What more do I have to produce to show my issues/problems inside a protected internal environment?

1 Like

I’m not sure I understand what you mean here. What’s the “smart thing”, exactly?

I’m a bit lost in the size of your comment frankly :sweat_smile:

If you don’t specify a resolver, it’ll use Go’s default which is outlined here:

That’s not for Caddy/Certmagic to control, I think, it’s up to the acmedns plugin to control how that’s resolved.

I agree there should be a way to turn off propagation checks, we’ll add this soon.

Yeah we could probably add a delay thing, but it’s probably not needed, we can just poll the issuer to see if it’s done yet.

PLEASE :slight_smile:

Okay, here you are contradicting the ACME_DNS plugin authors:

As noted in the Caddy forum thread, DNS propagation check is done by certmagic. Any option to resolve records differently or even to disable the propagation check would have to be implemented there, this plugin doesn’t have that kind of control. Closing the issue.

With the “smart thing” I meant it tries to go direct, instead of using system resolvers.

WHY does the Go resolver then go direct to the see the tcpdump. I believe it’s the certMagic that is at fault here, not the go resolver.

I’m pointing the evidences ;(

The propagation check is done by certmagic (i.e. checking for, but that’s not the same as resolving the domain (i.e. the acmedns server’s domain name).

Any communication done with the acmedns server to set the TXT record is done by the plugin. This is done here, via an HTTP request to your configured acmedns server:

I might be misunderstanding this discussion, but the propagation check is resolving <something> because certmagic is following a CNAME record (as it should): 3600 IN CNAME

Not because of something specific that acmedns plugin does. Relevant certmagic code.

But I think @Hendrik_Visage has a problem with the fact that certmagic sends a DNS query to authoritative nameservers directly instead of getting the TXT record from their DNS server. If I read the code correctly, certmagic tries to follow CNAME records when first attempt to fetch the TXT from the default DNS servers fails: code here.

@Hendrik_Visage , could you try restarting Caddy (forcing it to try to get a certificate) and then running

dig -t TXT

Does it find any TXT records?

1 Like

I think this is similar to a problem I experienced before. My default DNS resolver just wasn’t returning the TXT records in time and Caddy couldn’t verify the propagation (even though Let’s Encrypt would have been able to verify them). For me the solution was to use Cloudflare’s resolvers.

To check if this is the case with your resolver:

  1. Run Caddy so that it creates ACME DNS records.
  2. See if you can see these TXT records with your default DNS resolver in your restricted system:
    dig -t TXT
  3. See if you can see TXT records using Cloudflare resolvers (outside your restricted system):
    dig -t TXT @

If you see the TXT records with Cloudflare but you can’t see the records with your default DNS, there’s your problem - Caddy can’t find the records because your DNS resolver can’t. If that’s the case, the only solution would be to disable propagation checks.


And right there is the problem I’ve been trying to state in the subject field ;(

ie. Certmagic might NOT be able to check it, as it’s an OUTSIDE DNS, while the internal does NOT necessarily have, nor need those DNS entries CertMagic tries to check.

Certbot goes into a sleep, to “hope” it updates. I want a similar for CertMagic, especially where I could tell it to wait a configurable period and then continue with the solving.


The EXTERNAL DNS succesfully does find that record yes, the acmedns plugin does work correctly and as expected.

The INTERNAL DNS I need to coerce as it’s not setup for that, but could be cloned… not ideal for the dual/split DNS deployments I’m targeting, but doable.

The current CertMagic solution with 2.5.0-rc1: cut yet another hole in the firewall for DNS direct ;(

I’m basically looking at falling back to Certbot+ACMEDNS and then Caddy set to no auto-https ;(

Was hoping to not, but CertMAgic trying to “be smart” is the problem here ;(

For a system that is out there in the Big-Bad-Internet, doing what CertMagic is doing, is… well… nothing to worry about. But when you are inside a trusted and protected environment, doing things like those are, well… it’s destined for failure as firewalls etc. needs to protect, and direct stuff like CErtMagic does is definite no-no


Thank you @francislavoie !!!

The working config: (With custom xcaddy build since this is just pushed to master :wink: )

* {
	tls {
		issuer acme {
			dns acmedns /etc/acmedns/clientstorage.json
			propagation_delay 30s
			propagation_timeout -1
1 Like

This topic was automatically closed after 30 days. New replies are no longer allowed.