The Life of a DNS Zone: What Your Parent Publishes About You

ByLinuxtastic

September 3, 2026

A company changes DNS providers on a Friday. The new zone is byte-identical to the old one, checked record by record with dig @ns1.newprovider.net; the nameservers are changed at the registrar; the old provider is left running. Over the weekend the domain is dead for some customers and fine for others, monitoring is green, and both sets of nameservers answer correctly. The parent still publishes a DS record fingerprinting the old provider’s key, on a TTL of a day that nobody at either provider can change, and everyone behind a validating resolver gets SERVFAIL until it expires.

A zone has two publishers, you and your parent, and almost everything written about DNS assumes there is one. The parent publishes two facts about your zone, who serves it and which key may sign it, and nothing anywhere compares either with your zone. Six clocks decide when a change is finished; two of them are yours, and neither governs a nameserver change or a DNSSEC change. Every number here came off one machine: Ubuntu 24.04.4 with BIND 9.18.39, Knot DNS 3.3.4 and Unbound 1.19.2, running a signed root, TLD and zone on loopback with a primary, two secondaries and two validating resolvers. Those are the LTS versions, not upstream’s.

The six stages, and the one query that reads the parent.

  1. What the parent publishes about you: the delegation, the glue and the DS, none of which you can write.
  2. The zone, the serial and the copies: why a serial that goes backwards cannot be undone.
  3. Which copy answers: three servers, all authoritative, two different answers, no error anywhere.
  4. The chain the parent vouches for: a hash of a key, held by a stranger, never checked against your zone.
  5. The clocks: six of them, and four belong to somebody else.
  6. When the change is over: the only question you have, and the one with no global answer.

Ask a nameserver for the level above you, recursion off, DNSSEC on, and read the authority and additional sections:

DOMAIN=example.com
PARENT=$(dig +short NS "${DOMAIN#*.}" | head -1)
dig +norec +dnssec @"$PARENT" "$DOMAIN" A +noall +authority +additional
  • An NS set that is not the one in your zone. The parent’s list is the one used; yours is decorative. Stage 1.
  • An NS name inside your zone with no address beside it. Missing glue. Stage 1.
  • A named server does not answer, or answers without aa. It is in the rotation and not serving your zone. Stage 3.
  • Every named server answers with aa, and the SOA serials differ. The copies have diverged. Stage 2.
  • A DS here, and a validating resolver says SERVFAIL. The parent vouches for a key your zone no longer has. Stage 4, the branch that takes domains off the internet.
  • No DS at all, an NSEC or NSEC3 in its place, and you believe DNSSEC is on. Your signatures are ignored by everybody. Stage 4.
  • All of that correct, and a resolver still gives the old answer. Nothing is broken; a clock has not run out. Stages 5 and 6.

Two limits. This response is itself cached, at the parent’s TTL, so a resolver that asked before your change still holds the previous version; that is stage 6. And if your domain sits inside somebody else’s delegated subtree, your parent is not a registry, you have no channel to it, and most of stages 1 and 4 are unavailable to you. The client’s side of the wire is DNS, All the Way Down; buying the domain and choosing its records is Getting a Domain and Its DNS Right.

Stage 1: What the parent publishes about you

A registry holds three things about your domain, and you can write none of them directly:

What the registry actually stores.

  • The delegation NS set: the names of the servers resolvers will ask.
  • Glue: addresses, but only for nameserver names that sit inside the domain being delegated.
  • The DS record: a hash of one of your keys, if you use DNSSEC.

Your A records, your MX, your TXT and your TTLs live at your DNS provider; the registry has never seen them. Your registrar’s control panel is a channel to those three things, not a copy of them. There is no read-back path. The only way to see what is published is to ask a parent nameserver.

A real referral from the lab’s TLD server, recursion off, DNSSEC on. This is the parent’s entire opinion of the zone, in one packet:

$ dig +norec +dnssec @127.0.0.11 example.test A +noall +authority +additional
example.test.  3600  IN  NS     ns1.example.test.
example.test.  3600  IN  NS     ns2.example.test.
example.test.  3600  IN  NS     ns3.example.test.
example.test.  3600  IN  DS     24922 13 2 BC2049B4...8CA1808C
example.test.  3600  IN  RRSIG  DS 13 2 3600 20261003215802 20260903215802 48667 test. ...
ns1.example.test.  3600  IN  A   127.0.0.21
ns2.example.test.  3600  IN  A   127.0.0.22
ns3.example.test.  3600  IN  A   127.0.0.23

The NS records decide which servers get asked; the addresses under them are glue; the DS decides which key of yours may sign; the RRSIG proves the DS came from the parent. The NS set carries no signature. It is not authoritative data and DNSSEC does not protect it. The child’s copy of the same list is signed, by the child. Two copies in two zones, and nothing in any protocol, implementation or registry check ever compares them. In this lab they disagreed for hours and nothing logged anything.

The command everybody runs shows the wrong list

dig example.com NS does not show the delegation. It asks your recursive resolver, which answers from cache with the child’s apex NS set. Here the parent published ns1, ns2, ns3 and the zone published ns1, ns2, ns4:

$ dig +norec @127.0.0.11 example.test NS +short | sort | tr '\n' ' '   # the parent
ns1.example.test. ns2.example.test. ns3.example.test.

$ dig @127.0.0.30 example.test NS +short | sort | tr '\n' ' '          # Unbound
ns1.example.test. ns2.example.test. ns4.example.test.
$ dig @127.0.0.31 example.test NS +short | sort | tr '\n' ' '          # BIND
ns1.example.test. ns2.example.test. ns4.example.test.

In the exact case you would run this command to detect, the two lists disagreeing, it shows you the one nobody uses.

A server the parent does not name receives nothing

This is the belief that makes a spare nameserver look like insurance. multi.test was delegated by the parent to nsa only; the zone’s own NS set named nsa and nsb; nsb was up and answering correctly. Then nsa was stopped:

$ dig +norec @127.0.0.29 who.multi.test +short
203.0.113.29                       <- nsb, healthy, authoritative, answering

$ dig @127.0.0.31 who.multi.test | grep status:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 29813
$ dig @127.0.0.30 who.multi.test   <- Unbound: no answer in six seconds

Every query the resolver sent, in order, with the healthy server’s address appearing zero times:

IP 127.0.0.1.56128 > 127.0.0.31.53: A? who.multi.test.
IP 127.0.0.1.42382 > 127.0.0.10.53: NS? .
IP 127.0.0.1.54872 > 127.0.0.10.53: NS? test.
IP 127.0.0.1.45427 > 127.0.0.11.53: NS? multi.test.
IP 127.0.0.1.36563 > 127.0.0.28.53: A? who.multi.test.   <- the dead one
IP 127.0.0.31.53 > 127.0.0.1.56128: ServFail

$ tcpdump -r cap2.pcap -n | grep -c "127.0.0.29"
0

It holds with a warm cache too. Adding a nameserver to your zone does not add a nameserver. It adds a name to a list used for one thing, deciding who gets a NOTIFY (stage 2). The order matters: the new server must hold the zone before the delegation changes. Add it at the registrar first and you have delegated to a server answering REFUSED, which resolvers treat as lame for the whole of the parent’s TTL. Add it to your zone first and it gets NOTIFY but no traffic.

Glue

Glue is needed when a nameserver’s name is inside the zone it serves. There are two neighbouring cases, and one of them is how two of your own domains take each other down:

$ dig +norec @127.0.0.11 example.test A +noall +authority +additional
example.test.       3600  IN  NS  ns1.example.test.
ns1.example.test.   3600  IN  A   127.0.0.21     <- IN-DOMAIN glue: required

$ dig +norec @127.0.0.11 sibling.test A +noall +authority +additional
sibling.test.       3600  IN  NS  ns1.example.test.
ns1.example.test.   3600  IN  A   127.0.0.21     <- SIBLING glue: optional

$ dig +norec @127.0.0.11 external.test A +noall +authority +additional
external.test.      3600  IN  NS  ns.hoster.net. <- OUT OF BAILIWICK: no glue possible

Sibling-domain glue is optional. Some resolvers will not use it even when sent, so if a.example and b.example point at each other’s nameservers you are relying on a courtesy. Out-of-bailiwick names cost a second full resolution, which can itself fail. RFC 9471 (2023) requires a server to return all in-domain glue and to set the truncation bit rather than drop records, which matters now that the shipped EDNS buffer size is 1232 bytes.

Verify: run the hinge. The NS set should be exactly the set in your zone, every in-domain name should have an address beside it, and the DS, if you expect one, should be there with an RRSIG. Anything else is stage 1, fixed at a registrar rather than in a zone file.

Stage 2: The zone, the serial, and the copies

Your zone file is not the zone. It is one input to one of the copies, and the copy everybody reads is usually on a machine you do not own. The only thing connecting the copies is a 32-bit number in the SOA record.

It is not compared with >. It is compared with RFC 1982 serial arithmetic, in which “newer” means within half the number space: serial 5 is newer than 4294967290, and a serial you meant as a big increase can be a decrease. BIND prints the legal window when you get it wrong:

$ rndc reload example.test
zone reload queued

$ tail -2 named.log
zone example.test/IN: ixfr-from-differences: new serial (2026090302) out of range [2026090303 - 4173573949]
zone example.test/IN: not loaded due to errors.

rndc reload reported success and the zone did not reload. The upper bound is the serial plus 231−1. The usual consequence is not an outage but a silent no-op, which the operator experiences as slow propagation.

A serial that goes backwards cannot be undone

Restoring a zone file from a backup is offered everywhere as a rollback. It is not one. With a journal present, an older serial makes the load fail, and named logs all zones loaded, logs running, exits 0, keeps serving its other zones, and answers SERVFAIL with no aa bit for this one:

$ dig +norec @127.0.0.21 example.test SOA
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 19203
;; flags: qr; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

$ grep -E "journal|not loaded|all zones loaded|running" named.log
zone example.test/IN: journal rollforward failed: journal out of sync with zone
zone example.test/IN: not loaded due to errors.
all zones loaded
running

With the journal removed, it loads, and every secondary correctly refuses it. Both implementations, both right:

BIND: zone example.test/IN: serial number (2026090259) received from primary
      127.0.0.21#53 < ours (2026090309)
Knot: [example.test.] refresh, remote 127.0.0.21@53, remote serial 2026090259,
      remote is outdated

The zone is now permanently split, primary old, secondaries new, and no amount of waiting fixes it. The escape is to move the serial forward past the highest one anywhere, never backwards.

NOTIFY

The mechanism that keeps secondaries current is the SOA REFRESH timer; NOTIFY only shortens the wait. REFRESH is clamped by the secondary, so a low value in your zone file does nothing: BIND’s built-in bounds are min-refresh-time 300 and max-refresh-time 2419200, with retry clamped to 500 and 1209600 seconds.

The list of who receives a NOTIFY is not configured. It is the zone’s own apex NS set, minus the server named in the SOA. With notify yes and no also-notify, two packets went out, to the two other servers the zone names:

23:42:44.200005 IP 127.0.0.21.32969 > 127.0.0.22.53: notify SOA? example.test.
23:42:44.699905 IP 127.0.0.21.51445 > 127.0.0.23.53: notify SOA? example.test.

This is the mirror of the hinge. Query traffic comes from the parent’s list; NOTIFY comes from the child’s. A server missing from the first is invisible and starved; a server missing from the second is delegated and stale. What arrives is not reliably a delta: RFC 1995 lets a server answer IXFR with the whole zone, and BIND does whenever the delta exceeds max-ixfr-ratio, which on a signed zone is nearly always. One more BIND 9.18 default, printable with named -C: allow-transfer {any;}. Knot refuses by default.

The second hinge, for this stage. Ask every server the parent named for the SOA, and read two things — whether a line came back at all, and how the serials compare:

for ns in $(dig +norec @"$PARENT" "$DOMAIN" NS +short); do
  printf '%-28s ' "$ns"; dig +norec @"$ns" "$DOMAIN" SOA +short
done
  • A blank line. That server is in the delegation and is not serving the zone. This is the branch nobody checks, and it is the worst one.
  • Serials differ, and the secondary’s is lower. Ordinary lag. Find out whether the NOTIFY reached it.
  • Serials differ, and the secondary’s is higher. The primary went backwards. They will never converge on their own.
  • Serials all equal, and the data still differs. Two zones wearing the same number. Somebody edited a secondary.

Verify: run the second hinge. Every server the parent named should return a serial, all the same one. If a server returns nothing, go to stage 3: it is in the rotation.

Stage 3: Which copy answers

After a serial roll and one subsequent edit, the three servers the zone named were in two states, and all three set the authoritative-answer bit:

SERVER        SERIAL       www.example.test   flags
127.0.0.21    6            203.0.113.55       qr aa
127.0.0.22    6            203.0.113.55       qr aa
127.0.0.23    2026090309   203.0.113.77       qr aa

No error anywhere, no log line anywhere. Forty queries through the two resolvers, cache flushed between each:

Unbound:   20  203.0.113.77
BIND:      11  203.0.113.55
            9  203.0.113.77

BIND is a coin flip. Unbound went to the stale server twenty times out of twenty. The likely mechanism is its infrastructure cache preferring the server with the best measured round-trip time, and the best server being the wrong one; that is a probable explanation, and the ratio is what was measured.

Now the operator, running the check every guide recommends:

$ dig @127.0.0.30 www.example.test +short          # what the world is getting
203.0.113.77
$ dig +norec @127.0.0.21 www.example.test +short   # what the operator checks
203.0.113.55

dig @your-nameserver cannot detect any of the four commonest failures: a wrong delegation, a diverged secondary, a broken DS, and a cache that has not expired. It asks a machine you chose, and the resolvers do not.

The aa bit

aa distinguishes this server holds your zone from this server exists. A delegated server that has lost the zone answers without it; that is what “lame” means. Delegate a name to two servers, black-hole one and leave the other answering non-authoritatively:

BIND     20.02 s, then SERVFAIL
Unbound  no answer at all inside 60 s

named.log:  lame server resolving 'www.halflame.test' (in 'halflame.test'?): 127.0.0.11#53

A fully black-holed delegation behaves the same way. A server that refuses the connection is dealt with in 0.02 seconds, so a firewall that drops packets is far worse than a nameserver that is switched off. BIND’s lame-ttl now defaults to 0: it re-learns that a server is lame on every query.

Verify: for every server the parent named, dig +norec @$ns $DOMAIN SOA +noall +comments and look for aa in the flags line. Not for an answer, for the flag.

Stage 4: The chain the parent vouches for

The DS record is a hash of one of your keys, published by a stranger, and nothing ever checks it against your zone. A zone with no DS is still a signed zone; every resolver ignores the signatures and returns the answer without the ad bit. The DS does not make the signatures exist. It makes them checkable, and therefore mandatory. Here the parent published a DS for key tag 24922 while the zone signed with 58884. All three authoritative servers answered in milliseconds:

$ for ns in 127.0.0.21 127.0.0.22 127.0.0.23; do dig +norec @$ns www.example.test +short; done
203.0.113.77
203.0.113.77
203.0.113.77

$ dig @127.0.0.30 www.example.test | grep -E "status:|EDE"
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 60501
; EDE: 6 (DNSSEC Bogus): (validation failure <www.example.test. A IN>: no keys have
  a DS with algorithm ECDSAP256SHA256 from 127.0.0.22 for key example.test.
  while building chain of trust)

No aa check, no HTTP monitor and no dig @ns1 sees this. Only a validating resolver does: a large share of your users and none of your dashboards. Unbound 1.19.2 ships with ede: no; turning it on converts an opaque SERVFAIL into the RFC 8914 sentence above. BIND 9.18.39 returned no extended error for a bogus answer, and did for a stale one.

The ordering rule

The DS lives at the parent and carries the parent’s TTL, so every DNSSEC change is two changes on two clocks, and they must overlap. Publish the new DS alongside the old, wait a full DS TTL, move the signing, then remove the old DS. Never “remove, then change”: that takes the domain off the internet for everyone who has cached the old DS, and it is the sequence our own guide recommends.

Better, stop doing it by hand. CDS and CDNSKEY records publish your DS material in your own zone and let the registry take it from there (RFC 7344, 8078, 9615 and 9859). RFC 10026, published 23 July 2026 as BCP 246, tells registries to drop the DS TTL to five or fifteen minutes around a change and hold it there for a couple of days.

One event is not yours: on 11 October 2026 KSK-2024 becomes the key signing the root zone. It changes the trust anchor validating resolvers carry and requires nothing from a zone owner. A page telling you to prepare your zone for it has confused the root’s key with yours.

Verify: delv @<a validating resolver> $DOMAIN A prints fully validated or names the link that failed. Then compare the key tag in the parent’s DS, the first number in it, with dig +norec @$ns $DOMAIN DNSKEY | grep 257 piped through dnssec-dsfromkey -f -. Two numbers; they match, or your domain is down for everyone behind a validating resolver.

Stage 5: The clocks

Everything above happens instantly. What takes time is other people’s caches, and the corpus models that with one number, the TTL you set. There are six clocks. Two are yours, and neither governs either of the changes that take a domain down.

A negative answer lasts for min(SOA MINIMUM, the TTL of the SOA record itself, the resolver's own negative cap). DNS, All the Way Down says you need to lower both of the first two. It is a minimum: lowering either is sufficient. Measured with $TTL at 3600 and MINIMUM alone dropped to 60:

$ dig +norec @127.0.0.21 example.test SOA +noall +answer
example.test.  3600  IN  SOA  ns1.example.test. hostmaster.example.test. 2026090304 3600 900 1209600 60

$ dig +norec @127.0.0.21 stillnothere.example.test A +noall +authority
example.test.    60  IN  SOA  ns1.example.test. hostmaster.example.test. 2026090304 3600 900 1209600 60

Same record, same server, same second, two different TTLs, because the authoritative server applies the min() itself before putting the SOA into a negative answer. Both resolvers cached the “no” for sixty seconds. Read the authority section, not the answer section.

The clockWho sets itWhat it delaysWhere you read it
The record’s TTLyoua changed A, MX or TXT recordyour zone file
The negative TTLyou, then the resolvera name that did not exist when somebody askedthe authority section of an NXDOMAIN
The delegation NS TTLthe registryevery nameserver changethe hinge command, NS rows
The DS TTL, plus the validator’s bogus TTLthe registry, then the resolverevery DNSSEC changethe hinge command, DS row
The resolver’s ceiling and floorwhoever runs the resolvereverything you publishyou cannot — Unbound caps at 86400 positive and 3600 negative, BIND at 604800 and 10800
The stale windowwhoever runs the resolvereverything, after its TTL has expiredyou cannot — up to 86400 where it is on

Those values are documented software defaults, printable from named -C and unbound-control get_option. Per-TLD delegation TTLs are somebody else’s machine state; read your own with the hinge.

One zone with $TTL 604800 was cached by Unbound for 86400 and by BIND for 604800. The number in your zone file is a request. Serve-stale (RFC 8767) lets an expired record be served for up to a day. Both resolvers tested ship it off; the large public resolvers do not, so “wait one TTL” was never the rule. In BIND, stale-answer-enable yes alone does nothing, because stale-cache-enable defaults to false; with both on, a sixty-second record came back sixty-two seconds after expiry, carrying EDE: 3 (Stale Answer).

Verify: ask the resolvers your users use, without recursion, and read the TTL rather than the answer: dig +norecurse @1.1.1.1 www.example.com. A counting-down number is a cached copy and says how long is left. No answer means that resolver has not looked it up, the only completely good news at this stage.

Stage 6: When the change is over

There is no global check. The only evidence a change is finished is negative: the old servers stop being asked. A nameserver change takes effect at exactly the parent’s delegation NS TTL, not the answer’s TTL and not your zone’s own NS TTL. Here the answer’s TTL was 30 seconds, the zone’s NS TTL 3600 and the parent’s delegation TTL 120, and both resolvers switched at 120:

elapsed   Unbound        BIND
0s        203.0.113.28   203.0.113.28
 ...
105s      203.0.113.28   203.0.113.28
120s      203.0.113.29   203.0.113.29

A DNSSEC fix takes effect at the DS TTL plus the validator’s own bogus-answer timer. With a 90-second DS TTL, a fix live on the authoritative servers at t=0 reached BIND at 90 seconds and Unbound at 140, the extra 50 being Unbound’s val-bogus-ttl, default 60:

0s     Unbound=SERVFAIL       BIND=SERVFAIL
90s    Unbound=SERVFAIL       BIND=203.0.113.10
140s   Unbound=203.0.113.10   BIND=203.0.113.10

The fix was complete before anyone could see it, and it arrived at different people at different times. At a real registry the DS TTL is usually hours, and you read it rather than choose it; the hinge prints it.

Of the six clocks, which were yours? If you lowered the record’s TTL and the negative TTL in advance, everything remaining is somebody else’s number. Read them rather than wait on them: the parent’s with the hinge, the resolvers’ with dig +norecurse. And watch the old nameservers’ query log: it is the only place in the system where “finished” is observable, because it is the only place the absence of a question is recorded.

Verify: when the old nameservers have had no queries for your zone for longer than the parent’s delegation TTL, the change has reached everyone who was going to ask. That is why the guides that say leave the old servers running are right, for a reason they do not give: they are your only instrument.

A worked diagnosis: the Friday migration

Back to the Friday migration from the top of the page: a new provider whose zone is byte-identical to the old one, checked record by record with dig @ns1.newprovider.net; nameservers changed at the registrar on Friday afternoon; the old provider left running, as every guide including this site’s own advises.

Over the weekend, tickets arrive from customers who cannot reach the site. Not all of them, and not the same ones twice. The site is up. Monitoring is green. dig from three laptops is fine, dig @1.1.1.1 is fine, both sets of nameservers answer, and traffic on the old servers is falling as expected. The hinge, run once:

$ PARENT=$(dig +short NS com. | head -1)
$ dig +norec +dnssec @"$PARENT" example.com A +noall +authority +additional
example.com.  172800  IN  NS     ns1.newprovider.net.
example.com.  172800  IN  NS     ns2.newprovider.net.
example.com.   86400  IN  DS     41287 13 2 <the OLD provider's key>
example.com.   86400  IN  RRSIG  DS 13 2 86400 ...

The NS set is right. The DS is not: it fingerprints the old provider’s key signing key, and the new provider signs with its own. Nobody removed it, because nobody at either provider owns it. The DS lives at the registry, and the only party who can change it is the registrant, through a form most people have never opened.

It is intermittent rather than total because of stage 6. Resolvers pick up the new delegation as their own copy of the referral expires, and here that TTL is 172800, two days. The failure spreads, resolver by resolver, across a weekend, and the population affected is precisely the population behind a validating resolver.

The obvious fix makes it worse. “Turn DNSSEC off”, removing the DS, is what our own guide says, and it buys another 86400 seconds of the identical failure for everyone who has cached the bad one. The correct sequence is RFC 10026’s: publish the new DS alongside the old, wait a DS TTL, remove the old one, or hand the registry a CDS record and let it do the ordering.

Stage 4 says the DS is wrong. Stage 6 says why it is intermittent and when it ends, and an engineer who fixes the DS and goes home on Saturday gets the same tickets on Sunday. The operator owned every byte of both zones and was wrong about neither; the broken record was published by a party they had never spoken to, on behalf of a provider they had just left.

Symptoms, and which stage owns them

What you seeStageWhat to run, or what it is
A new nameserver is live and receiving no traffic at all1it is in your zone and not in the parent’s delegation
A nameserver you removed is still being queried1, 6the parent’s delegation NS TTL, which you did not set
The domain is dead for some resolvers and fine for others, with every server healthy4the DS does not match the key in the zone; delv names the link
Two of your nameservers give different answers, both with aa2, 3compare serials; then find out which one your resolver prefers
A secondary’s serial is higher than the primary’s2the primary went backwards; they will never converge
rndc reload succeeded and the change is not visible anywhere2the serial is not greater under RFC 1982; the zone did not load
Resolution takes twenty seconds and then fails3a lame or black-holed server in the delegation
You added a record and it still does not exist5the negative answer cached before you added it
A record is still being served after its TTL expired5serve-stale, for up to a day
dig $DOMAIN NS disagrees with your registrar1it is showing the child’s list; the parent’s is the one used
Everything above is correct and a resolver still gives the old answer6nothing is broken; read the clocks rather than waiting on them

Before you call it done

  1. Run the hinge against your own domain and read the NS set, the glue and the DS.
  2. Write down the parent’s NS TTL and DS TTL. They decide how long your next change takes, and you cannot edit either.
  3. Ask every server the parent named for the SOA: each one answers, sets aa, and returns the same serial.
  4. If you are signed, compare the DS key tag with your own key; delv against a validating resolver is the one-command version.
  5. Before any nameserver or DNSSEC change, write the order down: the new server holds the zone before the delegation moves; the new DS is published before the old one is removed. Overlap, never replace.

Related reading

  • DNS, All the Way Down — the eight stages on the client’s side of the same wire, and the page this one hands the negative-caching arithmetic back to.
  • Getting a Domain and Its DNS Right — buying the domain and choosing the records, and the page whose DNSSEC instruction this one exists to finish.
  • Server Migration — the other half of the weekend this page’s worked diagnosis happens on.