Chapter 06 · Part II · Running a zone

Zones, authoritative servers & transfers

Somebody has to write the answers down. A zone is a text file of records, one server holds the master copy, and several others keep exact copies so the zone survives when any one of them fails. This chapter is about that file, the SOA record that versions it, and the protocol that keeps the copies in step. If the DNS tree, records and caching are new to you, start with networks · DHCP & DNS; this picks up where it stops.

7fields in an SOA record's data: two names (MNAME, RNAME) and five 32-bit numbers (SERIAL, REFRESH, RETRY, EXPIRE, MINIMUM)
232possible serial numbers. RFC 1982 arithmetic treats them as points on a circle, so after 4,294,967,295 comes 0
231 − 1the largest amount you can add to a serial in one step (2,147,483,647) and still have every secondary see it as newer

Common mix-up: "primary" and "secondary" are about where the data comes from, not about who answers first. A resolver sees only the zone's NS records and treats every listed server as an equal authority; it does not look for the primary and it does not prefer it. The primary is often not listed in NS at all. What keeps the answers identical is the transfer machinery in this chapter, and when it breaks, different servers give different answers.

The master file

Writing a zone down

A zone is the part of the DNS tree that one set of servers is authoritative for: a domain, minus any subdomains that have been delegated away to someone else. Chapter 1 covers where those cuts fall. This chapter is about what happens inside one zone, starting with how it is written down.

The original format is the master file, defined in section 5 of RFC 1035 in 1987 and still read by BIND, NSD, Knot and PowerDNS today. People also call it a zone file. It is plain text, one record per line, and it is built for typing: anything you leave out is filled in from context. That makes zone files short. It also makes them the source of one of the oldest bugs in the DNS.

Here is a small zone, written the way an administrator would write it. It is simulated: every name and address on this page comes from the ranges reserved for documentation.

; example.com, as the admin typed it (simulated)
$ORIGIN example.com.
$TTL    1h
@        IN SOA  ns1 hostmaster (
                 2026102201 ; serial
                 2h         ; refresh
                 15m        ; retry
                 2w         ; expire
                 1h )       ; minimum: negative-caching TTL
         IN NS   ns1
         IN NS   ns2.example.net.
         IN MX   10 mail
ns1         A    192.0.2.53
www    300  A    192.0.2.10
mail        A    192.0.2.25

Five shortcuts are at work, and each one is a rule you can state exactly.

  • $ORIGIN sets the domain that every relative name is completed with. The server sets it to the zone's name before reading the file, so most files never say it; the line above just makes it visible.
  • Relative and absolute names. A name that ends in a dot is absolute and is used exactly as written. A name without the final dot is relative, and the current origin is appended to it. So ns1 means ns1.example.com. and ns2.example.net. means itself.
  • @ on its own means the origin. Here it is example.com., the apex of the zone.
  • Blank owner. A line that starts with a space or tab belongs to the same name as the record before it. The two NS lines and the MX line above all belong to the apex.
  • $TTL gives the TTL for any record that does not state one. It was not in RFC 1035; RFC 2308 added it in 1998, and it should be the first line of every file. Units such as 1h and 2w are a widely supported BIND convention; the protocol itself only carries seconds.

Parentheses let one record run over several lines, and a semicolon starts a comment that runs to the end of the line. That is why the SOA above can carry a label on each of its numbers.

www → www.example.com. · mail.example.com → mail.example.com.example.com.
The missing-trailing-dot bug. Write a full name but forget its final dot, and the origin is appended anyway. The file loads without complaint, because the result is a perfectly legal name; it just is not the one you meant. MX, NS, CNAME and SRV targets are where it bites, because the mistake is in the data, not in the owner, and nothing queries the broken name until mail stops arriving.
Go deeper: $INCLUDE, class and TTL inheritance, and the other formats

RFC 1035 defines two directives, $ORIGIN and $INCLUDE. $INCLUDE pulls in another file, optionally with its own origin, and the origin goes back to what it was when that file ends. RFC 2308 added $TTL. BIND adds a few of its own, such as $GENERATE for numbered runs of records; other servers may not accept them, so a file that uses them is no longer portable.

Before $TTL, a record with no TTL took the last TTL stated explicitly in the file, and the class likewise defaults to the last one stated. The TTL and class may come in either order after the owner, which is why a parser has to look at each token and decide which it is.

Not every zone lives in a text file. Many servers keep zones in a database and export or import master-file text only when asked, and hosted DNS providers show you a web form. The format still matters because it is what dig prints, what a transfer reproduces, and what you paste into a support ticket. Chapter 5 covers what each record type means; this chapter only cares how they are written and copied.

Instrument 1

Expand a zone file by hand

Type or paste a zone. The parser below applies the master-file rules as you type: it joins parenthesized lines, drops comments, follows $ORIGIN and $TTL, fills blank owners from the line above, decides which token is the TTL and which the class, and completes every relative name in the owner and in the data. The output is what the server actually loads, written fully qualified the way dig would print it. The part of each name that came from the origin is shown in blue; a name that probably lost its trailing dot is shown in magenta with a warning. The zone is simulated and nothing leaves your browser.

What the server loads

      
Records–
Names completed from origin–
Probably missing a dot–
SOA serial–

    The "probably missing a dot" check is a heuristic, the same idea linting tools use: a relative name that already ends in the zone's own name, or in a familiar top-level label such as com or net, almost certainly was meant to be absolute.

    Start of authority

    The SOA, field by field

    Every zone has exactly one SOA record, at its apex. It names the zone's source and carries the numbers that drive replication. Ask any of the zone's servers for it:

    $ dig +noall +answer example.com SOA          (simulated output)
    example.com.  3600  IN  SOA  ns1.example.com. hostmaster.example.com. 2026102201 7200 900 1209600 3600
    FieldValue hereWhat it controlsWho reads it
    MNAMEns1.example.com.The primary server: the original source of the zone's dataSecondaries sending NOTIFY, dynamic update clients (RFC 2136). Resolvers ignore it.
    RNAMEhostmaster.example.com.A mailbox for the person responsible. The first dot stands for @: this is hostmaster@example.com. A dot inside the local part is escaped as \.Humans
    SERIAL2026102201The zone's version number. Secondaries copy the zone only when it goes upSecondaries
    REFRESH7200 (2 h)How often a secondary asks the primary for the SOA to see whether the serial has changedSecondaries
    RETRY900 (15 min)How long to wait before asking again after a refresh failsSecondaries
    EXPIRE1209600 (14 days)How long a secondary keeps answering from its copy without a successful refresh. After that it stops answering for the zoneSecondaries
    MINIMUM3600 (1 h)Today: the TTL for negative answers, so how long resolvers may cache "no such name." Negative caching is Chapter 4Resolvers (RFC 2308)

    The first two fields are names and the last five are unsigned 32-bit numbers. Three of the timers, REFRESH, RETRY and EXPIRE, are only for secondaries; resolvers never look at them. The fourth, MINIMUM, is the one that changed meaning over the years, and it is the only one that reaches the wider internet.

    RFC 1912, the old but still useful guide to common DNS errors, gives the reasoning for each value. REFRESH is how long you can live with a secondary serving out-of-date data. RETRY is usually a fraction of REFRESH. EXPIRE should be longer than any outage you expect, so a secondary survives a long one, and it must be longer than RETRY and MINIMUM. Once NOTIFY is in place, REFRESH matters much less, because changes no longer wait for it.

    Go deeper: the three lives of MINIMUM

    RFC 1035 defined MINIMUM as the minimum TTL for every record in the zone. Servers never really enforced that. In practice it was used as the default TTL for records that did not give one, and some software used it as the TTL for negative answers too. RFC 2308 (1998) settled it: MINIMUM is the TTL of negative answers, and the default record TTL moved to the new $TTL directive. A resolver caches a negative answer for the smaller of MINIMUM and the SOA record's own TTL.

    That is why a file without $TTL is worth fixing. Different servers handle the missing default differently, and some fall back to MINIMUM with a warning in their log, which may be much shorter or longer than you intended.

    Version numbers that wrap

    The serial, and arithmetic on a circle

    The serial is a version number, and the rule a secondary follows is simple: if the primary's serial is greater than mine, my copy is old, so fetch the new one. Change the zone without raising the serial and no secondary will ever fetch the change. That is the most common replication bug there is, and Instrument 2 lets you commit it.

    "Greater than" needs care, because the serial is only 32 bits and it is allowed to wrap round. RFC 1982 defines serial number arithmetic for this. Picture the 4,294,967,296 possible serials around a circle. From any serial, the half of the circle ahead of it counts as newer and the half behind counts as older. A serial exactly half way round is neither: the comparison is undefined, and software may do anything.

    s2 is newer than s1 ⇔ 0 < (s2 − s1) mod 232 < 231
    RFC 1982 written as one test. Subtract, wrap the difference into the range 0 to 4,294,967,295, and compare it with 2,147,483,648. Smaller and it is newer; larger and it is older; exactly equal and the answer is undefined. So 0 is newer than 4,294,967,295, because it is one step ahead round the circle.

    Two conventions are common for choosing serials. Some people simply add 1 each time. Many use the date: YYYYMMDDnn, so 2026102201 is the first change on October 22, 2026 and 2026102202 is the second. Dates sort correctly, tell you when the zone last changed, and still fit in 32 bits until the year 4294. The scheme's one weakness is that it allows only 100 changes a day; zones changed by software often switch to a counter or to the Unix time in seconds.

    The circle explains the classic accident. Someone means 2026102201 and types 2062102201. The secondaries copy it, because it is newer. Fixing the typo by loading 2026102202 does nothing: from 2062102201, the number 2026102202 is behind, so every secondary decides it already has a newer zone and ignores the fix. You cannot go backward. You go forward round the circle, in steps of less than half.

    1. Add 2,147,483,647 (that is 231 − 1) to the bad serial, wrapping past 4,294,967,295. Load that. Every secondary sees it as newer and copies it.
    2. Wait until every secondary has it: RFC 1912 suggests two REFRESH periods; with NOTIFY, check each server with dig +nssearch.
    3. If your target is now ahead of the serial you loaded, load the target. If not, repeat step 1. Instrument 3 does the arithmetic.
    Go deeper: why the comparison is undefined at exactly half way

    Take 0 and 2,147,483,648. Going forward from 0 to the other is exactly half the circle, and going forward from the other back to 0 is also exactly half. Any rule that called one of them greater would, applied to the pair the other way round, call the other one greater too, so the answer would depend on which number you asked about first. RFC 1982 chose to leave the case undefined rather than pick a rule that is inconsistent. That is also why the largest safe step is 231 − 1, one short of half.

    RFC 1982 also defines only addition, and only of numbers up to that limit. You never subtract from a serial, and you never compare serials that are more than half the circle apart and expect a sensible answer. A secondary that was switched off for a very long time while the serial raced ahead is one of the rare places that could happen.

    Instrument 3

    Compare two serials, fix a bad one

    Compare mode: enter the serial a secondary holds and the serial the primary now has. The circle shows both, with the half that counts as newer than the secondary's serial shaded, and the verdict is the one a secondary following RFC 1982 would reach. Recover mode: enter a serial that went out too high and the serial you wanted; the calculator plans the steps, checks each one against RFC 1982, and draws the walk round the circle.

    –
    Forward distance–
    Share of the circle–
    Today, date style–
    Keeping copies in step

    Primaries, secondaries & NOTIFY

    Every zone should have at least two authoritative servers, and usually has more. One of them, the primary, holds the zone as the administrator edits it, from a file, a database or a provider's API. The others are secondaries: they load the zone from the primary over the DNS protocol itself and answer from their copy. Older documents call them master and slave; RFC 9499, the current DNS terminology reference, uses primary and secondary. A secondary can also feed further secondaries, so the source a server copies from is just "its primary."

    The original sync loop is polling, and it runs on the SOA timers. Every REFRESH seconds the secondary asks the primary a single small question, the SOA of the zone, and compares serials. Same serial: nothing to do, try again in REFRESH. Bigger serial: transfer the zone. No answer: try again in RETRY, and keep trying. If no refresh has succeeded for EXPIRE seconds, the copy is considered too old to be authoritative, and the secondary stops answering for the zone. Resolvers that ask it then get SERVFAIL, and fall back to other servers if they can.

    Polling alone means a change can take up to a whole REFRESH interval to reach a secondary. RFC 1996 fixed that in 1996 with NOTIFY: when the zone changes, the primary sends each secondary a short message saying the zone may have changed. The secondary then does exactly what it would have done when its timer fired, asks for the SOA and compares, so a forged or stale NOTIFY can at worst cause an unnecessary check. The primary may wait a short random time before notifying, so a hundred secondaries do not all ask at once. Polling stays on underneath as the safety net for lost messages.

    MechanismDefined inWhat crosses the wireWhen it is used
    SOA queryRFC 1034 / 1035One question, one record backEvery refresh and after every NOTIFY, to compare serials
    AXFRRFC 5936 (first in RFC 1034/1035)The whole zone, SOA first and SOA last, over TCPFirst load, or when the difference is not available
    IXFRRFC 1995Only the differences between two serials: records deleted, then records added, for each version stepRoutine changes to a large zone
    NOTIFYRFC 1996"Zone X may have changed," plus the new SOA as a hintRight after the primary loads a new serial

    AXFR copies everything. The response is the zone's SOA, then every other record, then the SOA again so the receiver knows it has the end. RFC 5936 pinned down the details that RFC 1035 left loose: AXFR runs over TCP, and the response may be split across many messages. IXFR sends only what changed. The secondary includes the serial it has; the primary replies with the deletions and additions that lead from that serial to the current one, or, if it no longer remembers that far back, falls back to a full transfer. For a zone with a million records and ten changes a day, the difference is enormous.

    A popular design is the hidden primary. The primary sits somewhere private and is not in the zone's NS records, so no resolver ever queries it. It exists only to feed the secondaries, which are the public face of the zone. Signing keys, admin tools and the database stay off the internet, and an attack on the public servers cannot reach the source of truth. RFC 1996 calls a server like this a stealth server; RFC 2182 discusses the same idea.

    Go deeper: what an IXFR answer looks like

    An IXFR response is a sequence of SOA records used as fences. It opens with the current SOA. Then, for each change from the secondary's version forward, it gives the old SOA followed by the records to delete, and the new SOA followed by the records to add. It closes with the current SOA again. If the change log is gone, the server may answer with what is in effect a full AXFR instead; the client can tell by the shape of the answer.

    ; IXFR from 2026102201 to 2026102202 (simulated, shortened)
    example.com.  SOA ... 2026102202 ...   ; current version
    example.com.  SOA ... 2026102201 ...   ; delete these from 01:
    www.example.com.  300  A  192.0.2.10
    example.com.  SOA ... 2026102202 ...   ; add these to make 02:
    www.example.com.  300  A  192.0.2.11
    example.com.  SOA ... 2026102202 ...   ; end

    Dynamic update (RFC 2136) is the other way records reach a primary: a client sends add and delete instructions as a DNS message, and the primary applies them, bumps the serial and notifies its secondaries. Laptops and DHCP servers registering names on a local network is the common case, covered in Chapter 10.

    Instrument 2

    Run a primary and two secondaries

    Three simulated servers for example.com: the primary ns1 and the secondaries ns2 and ns3. The secondaries really poll on REFRESH, fall back to RETRY when the primary does not answer, and stop answering when EXPIRE runs out; NOTIFY really triggers an immediate check. Each lane shows what that server would answer over time (up to the last eight simulated hours): blue for the current zone, orange for a stale copy, magenta for down or SERVFAIL. Try editing without bumping the serial, or taking the primary down and waiting. The timers are minutes so the story fits on screen; real zones use hours and weeks.

    Clock (simulated)–
    ns1 · primary–
    ns2 · secondary–
    ns3 · secondary–

      Who may copy the zone

      Protecting transfers

      The original DNS assumed that anyone could copy any zone. A zone transfer was a convenience for operators, and the data was public anyway, since anyone can look up any single name. The difference is scale. One lookup answers one question; one AXFR hands over the complete inventory of the zone: every host name, every internal-sounding label, every mail server and test machine, without any guessing. RFC 5936 says plainly that administrators may restrict AXFR, to keep the bulk zone private or to protect the server from the load.

      The defensive picture is simple. An authoritative server should refuse AXFR and IXFR from everyone except the secondaries that need them, and every server software's default is now to refuse or to require configuration. Checking your own zone is one command, run from a network that is not one of your secondaries: the answer you want is a refusal.

      $ dig axfr example.com @ns2.example.net        (your own zone, from outside; simulated)
      ; <<>> DiG <<>> axfr example.com @ns2.example.net
      ; Transfer failed.                          ← what you want to see

      There are two layers of protection, and good setups use both.

      • Address lists. The primary allows transfers only to the secondaries' addresses, and each secondary accepts NOTIFY only from its primary. Easy and useful, but an address alone is weak proof: on some networks it can be spoofed or borrowed, and it says nothing about whether the data was altered on the way.
      • TSIG. Transaction signatures, RFC 8945. Primary and secondary share a secret key, and each signs its messages with an HMAC computed over the message and the current time. The receiver recomputes the HMAC; if the message was changed, sent by someone without the key, or is too old, it fails. RFC 8945 makes hmac-sha256 mandatory to implement and recommends a 300-second window for clock differences, so the two servers' clocks must agree to within a few minutes. TSIG also protects NOTIFY and dynamic update.

      TSIG proves who is talking and that nothing was changed, but it does not hide the zone from someone watching the network path. RFC 9103 (2021) adds zone transfer over TLS, known as XoT, for zones where the contents themselves are sensitive. DNSSEC is a different tool for a different problem: it lets resolvers verify the records they receive, but it does not decide who may copy the zone.

      Go deeper: what a TSIG key looks like, and what it does not do

      A TSIG key has a name, which both ends must agree on exactly, an algorithm, and a random secret. Tools such as BIND's tsig-keygen generate one; you put the same block in both servers' configuration and tell each to use it for that peer. The example below is a shape, not a key: the secret is a placeholder.

      // primary and secondary both get this block (illustration only)
      key "ns1-ns2.example.com" {
          algorithm hmac-sha256;
          secret "<base64 secret generated on your own server>";
      };

      Treat the secret like a password: keep it out of version control and out of zone files, give each pair of servers its own key so one leak does not unlock everything, and replace keys when people with access leave. A key shared by every server in an organization turns one compromise into all of them.

      TSIG is symmetric: both ends hold the same secret, so either one could forge the other's messages. That is fine between two servers run by the same people or by contract partners. It is why DNSSEC, which must be checkable by strangers, uses public-key signatures instead.

      Diversity and delegation

      Where the servers go, and the lame ones

      Secondaries exist so that one failure does not take the zone off the internet. That only works if they do not share the failure. RFC 2182, written in 1997 to guide the choice of secondaries, puts it directly: secondary servers must be placed at both topologically and geographically dispersed locations, to minimise the likelihood of a single failure disabling all of them. It specifically warns against putting all of a zone's servers on the same LAN segment in the same room, and it applies the same logic to a single network provider. Two servers behind one router, one power feed or one upstream provider are, for this purpose, one server.

      The modern version of the same mistake is putting every NS record with one DNS provider. Many large organizations now list name servers from two independent providers, which works with the primary-and-secondary model in this chapter as long as both providers can transfer the zone from a common source, or are both fed by the same automation. Chapter 9 covers anycast, which lets one server name stand for many machines; it helps, but one provider's anycast cloud is still one provider.

      Then there is the delegation itself. A zone's name servers are listed twice: once in the parent zone, as the delegation NS records (plus glue addresses when needed), and once in the zone's own apex, the child NS set. Resolvers follow the parent's list to find the zone and then often prefer the child's. The two lists are meant to match, and when they drift apart, failures become intermittent and hard to reproduce: it depends which list a given resolver happens to have cached.

      A lame delegation is a server that is listed as authoritative for a zone but does not actually serve it. Ask it and it answers with a refusal, a referral elsewhere, an answer without the authoritative flag, or nothing at all. It usually happens quietly: a zone moves to a new provider and the old servers are never removed from the parent, a secondary is decommissioned but still listed, or a typo in an NS record points at a machine that has never heard of the zone. Resolvers waste time on the lame server and fall back to the others, so the zone limps along slowly until the day the working servers fail too.

      ; compare every listed server's SOA in one go (simulated output)
      $ dig +nssearch example.com
      SOA ns1.example.com. hostmaster.example.com. 2026102202 7200 900 1209600 3600 from server 192.0.2.53 in 11 ms.
      SOA ns1.example.com. hostmaster.example.com. 2026102202 7200 900 1209600 3600 from server 198.51.100.53 in 24 ms.
      SOA ns1.example.com. hostmaster.example.com. 2026102201 7200 900 1209600 3600 from server 203.0.113.53 in 87 ms.  ← one secondary is behind
      FailureSymptomHow to see itFix
      Serial not raisedSome servers give the new answer, some the old, indefinitelySame serial everywhere, different dataRaise the serial on every change; let tooling do it
      Serial set too highLater fixes never reach the secondariesSecondaries' serial is ahead of the one you loadStep forward round the circle (Instrument 3)
      Transfers blockedA secondary falls behind, then SERVFAILs after EXPIREdig +nssearch shows different serialsCheck the allow list, TSIG key name and clock
      Lame delegationSlow or intermittent lookupsAsk each listed server directly with recursion off: no authoritative answerRemove it from the parent and child NS sets, or make it serve the zone
      Parent and child NS differBehavior varies by resolver and by timeCompare the parent's delegation with the zone's own NSUpdate the registrar's delegation and the apex NS together
      No diversityOne outage takes the zone off the internetAll NS addresses in one network or one providerAdd a secondary elsewhere (RFC 2182)
      Open AXFRThe whole zone can be listed by anyonedig axfr against your own servers from outsideAllow transfers only to secondaries, with TSIG
      Go deeper: checking a delegation by hand, and with DNSViz

      To see the parent's view, ask one of the parent zone's servers for your NS records with recursion turned off, dig +norec; the answer arrives in the authority section as a referral. To see the child's view, ask each of your own servers the same question. Each listed server should answer with the authoritative-answer flag (aa) set, the same NS set and the same serial. Chapter 14 walks through reading those answers line by line.

      DNSViz (dnsviz.net) does this for a whole delegation chain at once and draws it as a graph, flagging lame servers, NS mismatches, missing glue and DNSSEC errors. It is a good first stop when a zone "works for me" but not for someone else, and RFC 9471 (2023) now spells out what glue authoritative servers must include in referrals.

      Cheat sheet

      Terms from this chapter

      Zone
      The part of the DNS tree that one set of authoritative servers answers for: a domain minus any subdomains delegated elsewhere.
      Master file
      The text format for a zone, RFC 1035 section 5: one record per line, with $ORIGIN, $TTL, @ and blank owners as shorthand. Also called a zone file.
      $ORIGIN
      The domain appended to every relative name in a zone file. Starts as the zone's own name.
      SOA record
      Start of authority: one per zone, at the apex. Seven fields: MNAME, RNAME, SERIAL, REFRESH, RETRY, EXPIRE, MINIMUM.
      Serial number
      The zone's 32-bit version number. Secondaries copy the zone only when it increases, compared with RFC 1982 arithmetic.
      Serial number arithmetic
      RFC 1982 comparison on a circle of 232 values: less than half way ahead is newer, exactly half way is undefined.
      Primary / secondary
      The server that holds the zone as edited, and the servers that copy it by zone transfer. Older names: master and slave.
      Hidden primary
      A primary not listed in the zone's NS records, so it feeds secondaries but never answers the public.
      NOTIFY
      RFC 1996 message from primary to secondary saying the zone may have changed, prompting an immediate serial check.
      AXFR / IXFR
      Full zone transfer (RFC 5936) and incremental transfer of only the changes between two serials (RFC 1995).
      TSIG
      Transaction signature (RFC 8945): an HMAC with a shared secret that authenticates transfers, NOTIFY and updates between two servers.
      Lame delegation
      A server listed in a zone's NS records that does not actually serve the zone authoritatively.
      Where this comes from

      Sources