dig against a public resolver returns SERVFAIL. The zone itself is fine. The problem is one level up, at the registry, where a DS record still points at DNSSEC keys that only the old provider ever had.
This article is written as a post-mortem of how this kind of incident usually unfolds. It covers the impact, the investigation, the point where the cause becomes clear, the quick mitigation, and the change in process that stops it from happening again. If you only want the fix, skip to the last two sections.
Initial impact: why only some people see it
Investigation: ruling out the usual suspects
+cd flag sets the Checking Disabled bit, which tells the resolver to return the data without DNSSEC validation. The +dnssec flag requests DNSSEC records in the response, so you can see whether signatures are present.
BASH
# Normal query through a validating resolver
dig example.com A @1.1.1.1 +dnssec
# Same query with validation disabled
dig example.com A @1.1.1.1 +dnssec +cdstatus: SERVFAIL and the second returns status: NOERROR with the correct IP, the records are fine and validation is the problem. A recent dig talking to a resolver that supports Extended DNS Errors may also print an EDE line. DNSKEY Missing or DNSSEC Bogus there points straight at a broken chain of trust. If your dig or resolver does not show EDE, the +cd comparison tells you the same thing.
If you query a non-validating resolver, both requests succeed. That is why testing from only your own network can make everything look healthy.
The discovery: a DS record nobody updated
.com. The TLD vouches for your domain through a DS (Delegation Signer) record. A DS record holds a hash of your zone's key-signing key, the DNSKEY record with flag 257. The DS lives in the parent zone, not in your zone. You publish it through your registrar, and the registry serves it.
When the old provider signed your zone, its key went into a DS record at the registry. Changing the nameservers did not change that DS. Many registrars leave existing DS records alone when nameservers change. So the parent still tells resolvers that this domain is signed with a specific key. Cloudflare's nameservers either serve no DNSKEY at all, because DNSSEC is not enabled there yet, or serve a different key that does not match. In both cases validation fails.
To confirm this, compare what the parent publishes with what the new nameservers serve:
BASH
# Find the TLD's nameservers, then ask one directly for your DS record
dig com NS +short
dig example.com DS @a.gtld-servers.net +norecurse
# Ask your assigned Cloudflare nameserver for the zone's keys
dig example.com DNSKEY @your-assigned-name.ns.cloudflare.com +dnssec +multicom and the gtld-servers.net host with the values for your own TLD, and use the nameserver names Cloudflare assigned to your zone.
TEXT
; Illustrative output format: DS record still published at the parent
example.com. 86400 IN DS 12345 8 2 <hex digest from the old provider>
; Illustrative output format: DNSKEY query to the new nameserver
;; ANSWER SECTION is empty, or contains a key with a different key id and algorithm+multi, dig prints each DNSKEY with a comment showing its key id and algorithm. If the DS key tag does not match any key id that Cloudflare serves, or no DNSKEY comes back at all, you have found the cause.
Temporary mitigation: remove the stale DS and wait out the caches
dig ... DS output to know how long you are waiting. A few public resolvers offer a cache flush tool for a single domain, which can speed things up for that resolver only.
You could also switch the nameservers back to the old provider. That only works if the old provider is still serving the signed zone. It is also slow, because NS records at the parent are cached as well. In most cases, removing the DS is cleaner.
The architectural fix: sign on Cloudflare, then publish the new DS
- Confirm the parent no longer returns a DS record. Run the
+norecurseDS query against the TLD nameserver and check that the answer section is empty. - Enable DNSSEC for the zone in Cloudflare. Cloudflare then shows the DS values to publish: key tag, algorithm, digest type, and digest. Some registrars ask for the DNSKEY public key instead of the DS, so check which form yours expects.
- Confirm that Cloudflare's nameservers now return a DNSKEY, and that
+dnssecqueries return RRSIG records alongside your answers. - Add the new DS at the registrar and copy every field exactly. A single wrong character produces the same SERVFAIL you just fixed.
- After the parent publishes the new DS, query a validating resolver again. A response with
NOERRORand thead(Authenticated Data) flag in the header means the chain validates from the root to your records.
+cd comparison before anything else. If turning off validation makes the answer appear, stop looking at the zone and look at the DS record at the parent. Then add a DS check to your migration checklist, before the nameservers change rather than after.