A longer delay may be needed after deploying a DNS-01 challenge #625

Closed
opened 2025-12-29 01:27:59 +01:00 by adam · 3 comments
Owner

Originally created by @senarvi on GitHub (Oct 1, 2024).

I'm using Dehydrated to sign certificates for a DuckDNS domain. Recently Dehydrated stopped working. This is the error that I was seeing:

 + Challenge validation has failed :(
ERROR: Challenge is invalid! (returned: invalid) (result: ["type"]      "dns-01"
["url"] "https://acme-v02.api.letsencrypt.org/acme/chall-v3/..."
["status"]      "invalid"
["validated"]   "2024-10-01T07:09:05Z"
["error","type"]        "urn:ietf:params:acme:error:unauthorized"
["error","detail"]      "During secondary validation: Incorrect TXT record \"\" found at _acme-challenge.....duckdns.org"
["error","status"]      403
["error"]       {"type":"urn:ietf:params:acme:error:unauthorized","detail":"During secondary validation: Incorrect TXT record \"\" found at _acme-challenge.....duckdns.org","status":403}
["token"]       "..."
["validationRecord",0,"hostname"]       "....duckdns.org"
["validationRecord",0]  {"hostname":"....duckdns.org"}
["validationRecord"]    [{"hostname":"....duckdns.org"}])

Turned out that the error was caused by a too short delay after deploying the challenge. The problem is explained here:

When you add a TXT record at your DNS provider, it takes some time before your DNS provider has copied that record to all of their servers. Sometimes this can take a minute, sometimes 10 minutes, occasionally longer, depending on the provider. If your ACME client submits a validation request before the TXT record for the DNS-01 challenge is ready at all your DNS provider’s servers, Let’s Encrypt may get an NXDOMAIN response, which will cause validation to fail. It depends on whether Let’s Encrypt happens to hit one of the servers that already has the TXT record or not. Now that we do multiple lookups, from multiple vantage points, it’s more likely that we’ll hit one of your DNS provider’s servers that hasn’t updated yet. Unfortunately, most DNS providers don’t provide an API that lets you check whether all servers are updated (Route53 is a notable exception). Your ACME client just needs to sleep a fairly generous amount of time between adding the TXT record and requesting validation.

I didn't find a way of controlling the delay after deploying the challenge. I solved the problem by adding a sleep in hook.sh:

case "$1" in
    "deploy_challenge")
        curl "https://www.duckdns.org/update?domains=$domain&token=$token&txt=$4"
        echo
        sleep 60
        ;;
Originally created by @senarvi on GitHub (Oct 1, 2024). I'm using Dehydrated to sign certificates for a DuckDNS domain. Recently Dehydrated stopped working. This is the error that I was seeing: ``` + Challenge validation has failed :( ERROR: Challenge is invalid! (returned: invalid) (result: ["type"] "dns-01" ["url"] "https://acme-v02.api.letsencrypt.org/acme/chall-v3/..." ["status"] "invalid" ["validated"] "2024-10-01T07:09:05Z" ["error","type"] "urn:ietf:params:acme:error:unauthorized" ["error","detail"] "During secondary validation: Incorrect TXT record \"\" found at _acme-challenge.....duckdns.org" ["error","status"] 403 ["error"] {"type":"urn:ietf:params:acme:error:unauthorized","detail":"During secondary validation: Incorrect TXT record \"\" found at _acme-challenge.....duckdns.org","status":403} ["token"] "..." ["validationRecord",0,"hostname"] "....duckdns.org" ["validationRecord",0] {"hostname":"....duckdns.org"} ["validationRecord"] [{"hostname":"....duckdns.org"}]) ``` Turned out that the error was caused by a too short delay after deploying the challenge. The problem is explained [here](https://community.letsencrypt.org/t/during-secondary-validation-incorrect-txt-record/113643): _When you add a TXT record at your DNS provider, it takes some time before your DNS provider has copied that record to all of their servers. Sometimes this can take a minute, sometimes 10 minutes, occasionally longer, depending on the provider. If your ACME client submits a validation request before the TXT record for the DNS-01 challenge is ready at all your DNS provider’s servers, Let’s Encrypt may get an NXDOMAIN response, which will cause validation to fail. It depends on whether Let’s Encrypt happens to hit one of the servers that already has the TXT record or not. Now that we do multiple lookups, from multiple vantage points, it’s more likely that we’ll hit one of your DNS provider’s servers that hasn’t updated yet. Unfortunately, most DNS providers don’t provide an API that lets you check whether all servers are updated (Route53 is a notable exception). Your ACME client just needs to sleep a fairly generous amount of time between adding the TXT record and requesting validation._ I didn't find a way of controlling the delay after deploying the challenge. I solved the problem by adding a `sleep` in `hook.sh`: ```bash case "$1" in "deploy_challenge") curl "https://www.duckdns.org/update?domains=$domain&token=$token&txt=$4" echo sleep 60 ;; ```
adam closed this issue 2025-12-29 01:27:59 +01:00
Author
Owner

@lukas2511 commented on GitHub (Oct 1, 2024):

This is intended behaviour. Dehydrated doesn't wait after the hook script returns. The hook script should check for propagation before returning control to dehydrated.

@lukas2511 commented on GitHub (Oct 1, 2024): This is intended behaviour. Dehydrated doesn't wait after the hook script returns. The hook script should check for propagation before returning control to dehydrated.
Author
Owner

@senarvi commented on GitHub (Oct 1, 2024):

Ok, good. I wasn't sure where this should be fixed, but I thought that it's worth mentioning anyway, in case someone else is fighting with the same problem.

@senarvi commented on GitHub (Oct 1, 2024): Ok, good. I wasn't sure where this should be fixed, but I thought that it's worth mentioning anyway, in case someone else is fighting with the same problem.
Author
Owner

@jahir commented on GitHub (Oct 2, 2024):

I had the same issue with dedyn.io (powered by desec.io, seems to not allow new dedyn.io registrations, unfortunately), so I query their DNS servers until the token appears there. unfortunately, this was not enough (maybe due to load-balancing or anycast), so let it settle after that for another while. here's the snippet from my hook script:

nslist=$(dig +short NS $DEDYN_NAME)
declare -i ts0=$(date +%s)
ok_count=0
while true; do
	sleep 1
	if [ $ok_count -eq 0 ]; then
		echo -n "."
	fi
	declare -i elapsed=$[$(date +%s)-$ts0]
	if [ $elapsed -ge 120 ]; then
		echo
		>&2 echo "$0: Token could not be published in 120 s. Please check your dedyn credentials."
		exit 5
	fi
	for ns in $nslist; do
		if ! dig -4 +short +nocookie TXT _acme-challenge.$DEDYN_NAME @${ns} | grep -q -- "$LE_TOKEN"; then
			ok_count=0
			continue 2
		fi
		if ! dig -6 +short +nocookie TXT _acme-challenge.$DEDYN_NAME @${ns} | grep -q -- "$LE_TOKEN"; then
			ok_count=0
			continue 2
		fi
	done
	let ++ok_count
	if [ $ok_count -le 10 ]; then
		echo -n "+"
		continue
	fi
	echo
	>&2 echo "$0: Ok, got token published (after $elapsed s)."
	sleep 5
	break
done

DEDYN_NAME is the domain name (yourhost.dedyn.io), LE_TOKEN is the LE token that is to be published (obviously). HTH.

@jahir commented on GitHub (Oct 2, 2024): I had the same issue with dedyn.io (powered by desec.io, seems to not allow new dedyn.io registrations, unfortunately), so I query their DNS servers until the token appears there. unfortunately, this was not enough (maybe due to load-balancing or anycast), so let it settle after that for another while. here's the snippet from my hook script: ``` nslist=$(dig +short NS $DEDYN_NAME) declare -i ts0=$(date +%s) ok_count=0 while true; do sleep 1 if [ $ok_count -eq 0 ]; then echo -n "." fi declare -i elapsed=$[$(date +%s)-$ts0] if [ $elapsed -ge 120 ]; then echo >&2 echo "$0: Token could not be published in 120 s. Please check your dedyn credentials." exit 5 fi for ns in $nslist; do if ! dig -4 +short +nocookie TXT _acme-challenge.$DEDYN_NAME @${ns} | grep -q -- "$LE_TOKEN"; then ok_count=0 continue 2 fi if ! dig -6 +short +nocookie TXT _acme-challenge.$DEDYN_NAME @${ns} | grep -q -- "$LE_TOKEN"; then ok_count=0 continue 2 fi done let ++ok_count if [ $ok_count -le 10 ]; then echo -n "+" continue fi echo >&2 echo "$0: Ok, got token published (after $elapsed s)." sleep 5 break done ``` DEDYN_NAME is the domain name (`yourhost.dedyn.io`), LE_TOKEN is the LE token that is to be published (obviously). HTH.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/dehydrated#625