NSDIFF(1p)
β¨ NSDIFF β bestie, it's giving zone diff energy π
okay so real talk, nsdiff comes from the Perl user-contributed manual pages (section 1p, periodt) and it is lowkey one of the most useful little tools in the DNS world. Let me put you on.
π NAME π
nsdiff β make an nsupdate script out of the differences between two DNS zone files.
π¦ SYNOPSIS π¦
nsdiff [-hV] [-b address] [-k keyfile] [-y [hmac:]name:key]
[-0|-1] [-q|-v [q][r]] [-cCdD] [-i regex] [-S mode|num]
[-u] [-s server] [-m server] <zone> [old] [new]
πΈ DESCRIPTION πΈ
So here's the vibe: nsdiff looks at the old and new versions of a DNS zone, figures out what changed, and prints those changes as a script that BIND's nsupdate program can run. That's it, that's the whole personality. π
It ignores DNSSEC-related differences, because the assumption is that the name server has sole control over zone keys and signatures. Not its business, not its problem, we move on.
The input files are typically in standard DNS zone file format. They get passed through BIND's named-compilezone program to convert them into canonical form β which means they can also be in BIND's "raw" format, and they may even have .jnl update journals. Iconic, honestly.
If you don't specify the old file, nsdiff will use dig to transfer the zone from the server you gave with the -s option β or, if you didn't give -s at all, it grabs the server from the zone's SOA MNAME field. And if you specify neither old nor new files, nsdiff transfers the new version of the zone from the server given by the -m option. Slay.
The SOA serial number gets special handling, bestie, listen up: any difference between the old and new serial numbers is ignored (except in -S file mode), because background DNSSEC signing activity can increment that serial number unpredictably and we are NOT about to let that ruin our diff. When the zones do differ, nsdiff sets the serial number according to the -S option, and it uses the old serial number to protect against conflicting updates. Protective king behavior. π
π OPTIONS π
-hβ shows you this documentation. that's it. you're welcome. π-Vβ spits out version information.-0β allows very large updates that affect one single domain name to be split across multiple requests. go big or go home.-1β aborts if the update does not fit in one request packet. all-or-nothing energy.-Cβ does not ignore CDS or CDNSKEY records. Normally those are managed bydnssec-settimewith the"-P sync"and"-D sync"options, but you can use this option if you're managing them some other way. In that case, your un-signed zone file should include the complete CDS and/or CDNSKEY RRset(s) β and if it doesn't,nsdiffwill delete the records. no cap. π-cβ compares records case-insensitively. helpful if thensupdatetarget server doesn't preserve the case of domain names. However (and this is important, bestie): with this option,nsdiffdoes not correctly handle records that only differ in case. so like, trade-offs. π-Dβ does not ignore DNSKEY records. sometimes you gotta take manual control over a zone's DNSKEY RRset β for instance, to include foreign DNSKEY records during a migration to or from another hosting provider. If you use this option, your un-signed zone file should include the complete DNSKEY RRset; if it doesn't,nsdiffwill try to delete the DNSKEY records. Normallynamedwill reject the update, unless the zone is configured with thednssec-secure-to-insecureoption.-dβ ignores DS records. this one is useful when you're managing secure delegations on the signing server (viansupdate) rather than in the source zone.-iregex β ignores more DNS records. by default,nsdiffstrips out DNSSEC RRs (except for DS) before comparing zones. You can exclude irrelevant changes from the diff by supplying a regex that matches the unwanted RRs. filter queen. π-mserver[#port] β transfer the new version of the zone from the server given in this option, for example a back-end hidden primary server. You can specify the server host name or IP address, optionally followed by a"#"and the port number.-sserver[#port] β transfer the old version of the zone from the server given in this option, using the same syntax as the-moption.-Sdate|file|serial|unix|num β choose the SOA serial number update mode:- the default,
file, takes the serial number from the new input zone dateuses a number of the formYYYYMMDDnnand allows for up to 100 updates per dayserialjust increments the serial number in the old input zoneunixuses the UNIX"seconds since the epoch"value
- the default,
You can also specify an explicit serial number value. In all cases, if the old input zone serial number is larger than the target value, it is just incremented. Serial number wrap-around is not supported. π
-qβ quiet / quick check. Output is suppressed unless the zones differ, in which case a short note is printed instead of annsupdatescript.-uβ tellsnsupdateto send the update message to the server specified in the-soption.-v[q][r] β control verbosity. Theqflag causes queries to be printed. Therflag causes responses to be printed. To makensdiffquiet, use-v ''.
The following options get passed to dig to modify its SOA and AXFR queries:
-baddress β source address fordigqueries.-kkeyfile β TSIG key file fordigqueries.-y[hmac:]name:key β literal TSIG key fordigqueries.
π EXIT STATUS π
The nsdiff utility returns 0 if the zones are the same, 1 if they differ, and 2 if there was an error. simple. clean. iconic.
π₯ DIAGNOSTICS π₯
"usage: ...""not a domain name: <zone>"
Errors in the command line. classic.
"could not get SOA record for <zone>"
Failed to retreive the zone's SOA using dig when trying to obtain the server MNAME from which to AXFR the zone.
"missing SOA record"
The output of named-compilezone is incomplete, usually because the input file is erroneous.
"<zone> has changes"
Printed instead of an nsupdate script when the -q option is used.
"update does not fit in packet"
The changes for one domain name did not fit in 64 KiB, or the -1 option was specified and all the changes did not fit in 64 KiB.
"ignoring dig options when loading zones from files"
Warning emitted when the command line includes options for dig as well as zone source files.
"ignoring -m option when loading new zone from file""need -m option when there are no input files"
The -m server option is required when there are no file arguments, and ignored otherwise.
"loading zone <zone> via AXFR from server""loading zone <zone> from file file"
Normal progress messages emitted before nsdiff invokes named-compilezone, to explain the latter's diagnostics.
πΈ EXAMPLE β DNSSEC πΈ
Obsessed with this one. The easiest way to deploy DNSSEC is to let named manage zone keys and signatures automatically, and feed changes into zones using DNS update requests. But that's very different from the traditional way of manually maintaining zones in standard DNS zone file format. nsdiff bridges that gap between the two operational styles. it's giving matchmaker. π«Ά
To support this workflow you need BIND-9.7 or newer. You'll keep maintaining your zone file $sourcefile like you always did, but just so you know β it is no longer the same as the $workingfile used by named. After you make a change, instead of running "rndc reload $zone", you run:
nsdiff $zone $sourcefile | nsupdate -l
Configure your zone like this, to support DNSSEC and local dynamic updates:
zone $zone {
type primary;
file "$workingfile";
auto-dnssec maintain;
update-policy local;
};
To create DNSSEC keys for your zone, change into named's working directory and run these commands:
dnssec-keygen -f KSK $zone
dnssec-keygen $zone
π§ EXAMPLE β bump-in-the-wire signing π§
A common arrangement for DNSSEC is to have a primary server that is oblivious to DNSSEC (living its best unbothered life), a signing server which transfers the zone from the primary and adds the DNSSEC records, and a bunch of secondary servers which transfer the zone from the signer and which are the public authoritative servers.
You can implement this with nsdiff, which handles the transfer of the zone from the primary to the signer. No modifications to the primary are necessary. You set up the signer as in the previous section. To transfer changes from the primary to the signer, run the following on the signer:
nsdiff -m $primary -s $signer $zone | nsupdate -l
π EXAMPLE β dynamic reverse DNS π
Say you have a reverse zone such as "2.0.192.in-addr.arpa" which is mostly managed dynamically by a DHCP server, but which also has some static records (for network equipment, say). You can maintain the static part in a DNS zone file and feed any changes into the live dynamic zone by telling nsdiff to ignore the dynamic entries. Say all the static equipment has IP addresses between 192.0.2.250 and 192.0.2.255, then you can run the command pipeline:
nsdiff -i '^(?!25\d\.)' 2.0.192.in-addr.arpa 2.0.192.static |
nsupdate -l
π CAVEATS π
okay bestie, listen, this part matters.
By default, nsdiff does not maintain the transactional semantics of native DNS update requests when the diff is big: it applies large changes in multiple update requests. To minimise the problems this may cause, nsdiff ensures each domain name's changes are all in the same update request.
There is still a small risk of clients not seeing a change applied atomically when that matters (e.g. altering an MX and creating the new target in the same transaction). You can avoid the risk by using the -1 option to prevent multi-packet updates, or by being careful about changes that depend on multiple domain names. careful king. π₯Ί
The update requests emitted by nsdiff include SOA serial number prerequisite checks to ensure that the zone has not changed while it is running. This can happen even in simple setups if named happens to be re-signing the zone at the time you make an update. Unfortunately, the DNS update protocol does not allow for good error reporting when a prerequisite check fails. You can use nspatch to cope with this problem.
π BUGS π
When updating a name's DNS records, nsdiff first deletes the old ones, then adds the new ones. This ensures that CNAME replacements and TTL changes work correctly. However β and this is the catch β this update strategy prevents you from replacing every record in a zone's apex NS RRset in one update, because it isn't possible to delete all a zone's name servers. yeah. that's a real one. π«
β VERSION β
This is nsdiff-1.85 <https://dotat.at/prog/nsdiff/>
Written by Tony Finch <fanf2@cam.ac.uk> <dot@dotat.at> at Cambridge University Information Services.
You may do anything with this. It has no warranty.
π ACKNOWLEDGMENTS π
Thanks to Athanasius, Mike Bristow, Piete Brooks (University of Cambridge Computer Laboratory), Terry Burton (University of Leicester), Owen Dunn (University of Cambridge Faculty of Mathematics), Martin Hartl (Barracuda), JP Mens, Mohamad Shidiq Purnama (PANDI), and Jordan Rieger (webnames.ca) for providing useful feedback. we love a credited queen β¨
π SEE ALSO π
nspatch(1), nsupdate(1), nsvi(1), dig(1), named(8), named-compilezone(8), perlre(1)
and that's the whole page, bestie!! π«Ά this one's from perl v5.40.1, dated 2026-01-26, and it lives in the NSDIFF(1p) manual. now go diff some zones and slay π
β¨
π¦ where this page comes from
- ubuntu resolute: nsdiff 1.85-2build1 Β· 0BSD OR MIT-0
- ubuntu stonking: nsdiff 1.85-2build1 Β· 0BSD OR MIT-0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms