LFCE 36 ๐ง BIND9 โ Zones and Records
A BIND9 zone file is the authoritative data source for a domain. It is a plain text file that declares the domain’s name servers, its mail exchangers, its host addresses, and the start-of-authority record that ties the whole zone together. The previous chapter configured the server to load a zone; this chapter explains what goes inside the zone file and why each record exists. A zone file that parses without error is not necessarily correctโa missing trailing dot, a stale serial number, or a CNAME at the zone apex can all produce a zone that loads but answers incorrectly.
The format is defined by RFC 1035 and refined by decades of operational practice. Every record follows the same structure: an owner name, an optional TTL, a class, a type, and the record data. The $TTL directive sets the default for the entire file, and the SOA record is mandatory and must appear first. The other recordsโNS, A, AAAA, CNAME, MX, TXT, PTRโdeclare the actual data that clients query for.
Key point: The SOA record’s serial number must increase every time the zone file changes. Secondary servers compare their serial against the primary’s, and a serial that does not increase prevents the secondary from transferring the updated zone . The refresh, retry, expire, and minimum fields in the SOA control how secondaries poll the primary, how long they wait between retries, when they stop answering queries if they cannot reach the primary, and how long negative answers are cached .
Why zone files require careful construction
The trailing-dot problem.
A domain name in a zone file that does not end with a dot is relative to the zone’s origin. ns1 becomes ns1.example.com. when the zone is example.com. But ns1.example.com without the trailing dot becomes ns1.example.com.example.com.โa name that does not exist. Every fully qualified name in a zone file must end with a dot, or the zone will append the origin again . This is the single most common syntax error in zone files, and it produces a zone that loads but has incorrect hostnames.
The SOA-serial problem.
The serial number is a 32-bit unsigned integer. Secondary servers use it to determine whether their copy of the zone is current. When the primary’s serial is greater than the secondary’s, the secondary requests a zone transfer. If the serial is the same or lower, the secondary does not update, even if the zone file’s contents have changed . The conventional format is YYYYMMDDNN, where NN is a two-digit revision counter for that day . A serial that exceeds the 32-bit limit wraps to zero, which can cause secondaries to stop updating. The practical limit is 4,294,967,295 .
The CNAME-apex problem.
A CNAME record creates an alias. It cannot coexist with any other record at the same owner name. If the zone apex (@) has an NS record, an MX record, and a TXT record for SPF, it cannot also have a CNAME. The apex must have A or AAAA records, not a CNAME. A CNAME at www pointing to @ is valid because www has no other records .
a. The SOA record and its fields
The SOA (Start of Authority) record declares the zone’s primary name server, the administrator’s email address, and the timing parameters that govern secondary server behavior. It is the first record in the file and is mandatory.
; Zone file for example.com
$TTL 86400 ; Default TTL: 1 day
@ IN SOA ns1.example.com. admin.example.com. (
2025010101 ; Serial: YYYYMMDDNN format
3600 ; Refresh: secondaries check every hour
900 ; Retry: retry after 15 minutes on failure
604800 ; Expire: stop answering after 1 week without contact
300 ; Minimum (negative TTL): cache NXDOMAIN for 5 minutes
)
The @ symbol represents the zone’s origin, which is example.com. in this case. The first name after SOA is the primary name server’s fully qualified domain name, ending with a dot. The second name is the administrator’s email address with the @ replaced by a dot and a trailing dot appended: admin@example.com becomes admin.example.com. .
The refresh value tells secondaries how often to check the primary’s serial. The retry value tells them how long to wait after a failed check before trying again. The expire value tells them when to stop answering queries if they have not successfully contacted the primaryโthis prevents secondaries from serving stale data indefinitely. The minimum field, in modern BIND, is the negative caching TTL: how long a resolver should cache an NXDOMAIN response .
The serial in this example is 2025010101. If the zone file is edited on January 2, 2025, the serial becomes 2025010201. If it is edited twice on that day, the serial becomes 2025010202. The serial must always increase, never decrease, and never wrap past the 32-bit maximum.
b. NS, A, AAAA, and CNAME records
The NS record declares an authoritative name server for the zone. Every zone must have at least one, and best practice is to have at least two for redundancy. The A and AAAA records map hostnames to IPv4 and IPv6 addresses. The CNAME record creates an alias.
; Name servers
@ IN NS ns1.example.com. ; Primary name server
@ IN NS ns2.example.com. ; Secondary name server
; Glue records for in-zone name servers
ns1 IN A 192.168.1.10
ns2 IN A 192.168.1.11
; Host addresses
@ IN A 192.168.1.20 ; Apex A record
@ IN AAAA 2001:db8::20 ; Apex AAAA record
www IN A 192.168.1.20 ; www A record
mail IN A 192.168.1.25 ; Mail server A record
mail IN AAAA 2001:db8::25 ; Mail server AAAA record
; Alias
ftp IN CNAME www ; ftp is an alias for www
The ns1 and ns2 records are called glue records when the name server is inside the zone it serves. Without glue, a resolver would need to resolve ns1.example.com before it could query it, which is a circular dependency. The glue A record breaks that cycle .
The apex A record (@ IN A 192.168.1.20) means the domain name itself resolves to an address. This is common for websites that serve content at example.com as well as www.example.com. The ftp CNAME points to www, so a query for ftp.example.com returns the same address as www.example.com .
c. MX, TXT, and PTR records
The MX record declares a mail exchanger for the domain. The TXT record holds arbitrary text, most commonly SPF and DMARC policies. The PTR record maps an IP address to a hostname in a reverse zone.
; Mail exchanger
@ IN MX 10 mail.example.com. ; Priority 10; lower is preferred
; SPF: only the mail host may send email for this domain
@ IN TXT "v=spf1 ip4:192.168.1.25 ip6:2001:db8::25 -all"
; DMARC: quarantine failures, send reports
_dmarc IN TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com"
The MX record’s priority field determines preference: the lower the number, the higher the preference. If multiple MX records exist, mail is delivered to the lowest-priority server first, and the next priority is tried only if the first fails . The trailing dot on mail.example.com. is required.
The TXT record’s value is a quoted string. The SPF record (v=spf1 ...) tells receiving mail servers which hosts are authorized to send email for the domain. The -all at the end means “reject all other senders.” The DMARC record at _dmarc.example.com tells receivers what to do when SPF or DKIM fails .
A reverse zone for the 192.168.1.0/24 subnet uses PTR records. The zone name is 1.168.192.in-addr.arpa, and the owner names are the last octet of the IP address.
; Reverse zone file for 192.168.1.0/24
$TTL 86400
@ IN SOA ns1.example.com. admin.example.com. (
2025010101 3600 900 604800 300
)
@ IN NS ns1.example.com.
10 IN PTR ns1.example.com. ; 192.168.1.10
11 IN PTR ns2.example.com. ; 192.168.1.11
20 IN PTR www.example.com. ; 192.168.1.20
25 IN PTR mail.example.com. ; 192.168.1.25
The PTR record’s owner name is the host part of the IP address. A query for 10.1.168.192.in-addr.arpa returns ns1.example.com. .
Complete Example Session
# ============================================
# PART 1: THE ZONE HEADER AND SOA
# ============================================
# Create the zone file with the SOA record
sudo tee /etc/bind/zones/example.com.zone > /dev/null <<'EOF'
$TTL 86400
@ IN SOA ns1.example.com. admin.example.com. (
2025010101 ; serial
3600 ; refresh
900 ; retry
604800 ; expire
300 ; negative TTL
)
EOF
# ============================================
# PART 2: THE NAME SERVER RECORDS
# ============================================
sudo tee -a /etc/bind/zones/example.com.zone > /dev/null <<'EOF'
@ IN NS ns1.example.com.
@ IN NS ns2.example.com.
EOF
# ============================================
# PART 3: THE GLUE RECORDS
# ============================================
sudo tee -a /etc/bind/zones/example.com.zone > /dev/null <<'EOF'
ns1 IN A 192.168.1.10
ns2 IN A 192.168.1.11
EOF
# ============================================
# PART 4: THE APEX ADDRESS RECORDS
# ============================================
sudo tee -a /etc/bind/zones/example.com.zone > /dev/null <<'EOF'
@ IN A 192.168.1.20
@ IN AAAA 2001:db8::20
EOF
# ============================================
# PART 5: THE HOST RECORDS
# ============================================
sudo tee -a /etc/bind/zones/example.com.zone > /dev/null <<'EOF'
www IN A 192.168.1.20
mail IN A 192.168.1.25
mail IN AAAA 2001:db8::25
ftp IN CNAME www
EOF
# ============================================
# PART 6: THE MAIL AND TXT RECORDS
# ============================================
sudo tee -a /etc/bind/zones/example.com.zone > /dev/null <<'EOF'
@ IN MX 10 mail.example.com.
@ IN TXT "v=spf1 ip4:192.168.1.25 ip6:2001:db8::25 -all"
_dmarc IN TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com"
EOF
# ============================================
# PART 7: THE REVERSE ZONE
# ============================================
sudo tee /etc/bind/zones/1.168.192.in-addr.arpa.zone > /dev/null <<'EOF'
$TTL 86400
@ IN SOA ns1.example.com. admin.example.com. (
2025010101 3600 900 604800 300
)
@ IN NS ns1.example.com.
10 IN PTR ns1.example.com.
11 IN PTR ns2.example.com.
20 IN PTR www.example.com.
25 IN PTR mail.example.com.
EOF
# ============================================
# PART 8: VALIDATE THE ZONES
# ============================================
sudo named-checkzone example.com /etc/bind/zones/example.com.zone
sudo named-checkzone 1.168.192.in-addr.arpa /etc/bind/zones/1.168.192.in-addr.arpa.zone
# ============================================
# PART 9: RELOAD AND TEST
# ============================================
sudo rndc reload
dig @localhost www.example.com A
dig @localhost example.com MX
dig @localhost -x 192.168.1.20
# ============================================
# PART 10: VERIFY THE SOA
# ============================================
dig @localhost example.com SOA
# Output shows the serial, refresh, retry, expire, and minimum
The ten parts build the zone file incrementally: the SOA header, the name servers, the glue records, the apex addresses, the host records, the mail and TXT records, the reverse zone, validation, reload, and SOA verification. The critical steps are Part 8 (validation before reload) and Part 9 (testing each record type with dig).
Quick Reference
Record Types
| Type | Purpose | Example |
|---|---|---|
SOA | Zone authority and timing | @ IN SOA ns1.example.com. admin.example.com. (...) |
NS | Authoritative name server | @ IN NS ns1.example.com. |
A | IPv4 address | www IN A 192.168.1.20 |
AAAA | IPv6 address | www IN AAAA 2001:db8::20 |
CNAME | Alias | ftp IN CNAME www |
MX | Mail exchanger | @ IN MX 10 mail.example.com. |
TXT | Arbitrary text (SPF, DMARC) | @ IN TXT "v=spf1 ..." |
PTR | Reverse mapping | 20 IN PTR www.example.com. |
SOA Fields
| Field | Meaning | Typical Value |
|---|---|---|
| Serial | Zone version; must increase | 2025010101 |
| Refresh | Secondary poll interval | 3600 (1 hour) |
| Retry | Retry interval after failure | 900 (15 min) |
| Expire | Stop answering if no contact | 604800 (1 week) |
| Minimum | Negative cache TTL | 300 (5 min) |
Validation Commands
| Command | Purpose |
|---|---|
named-checkzone <zone> <file> | Validate zone file syntax |
dig @server <name> <type> | Query a specific record type |
dig @server -x <ip> | Reverse lookup |
Best Practices
โ Do This:
# End every FQDN with a dot
@ IN NS ns1.example.com. # โ
# Increment the serial on every change
2025010101 โ 2025010102 # โ
# Use glue records for in-zone name servers
ns1 IN A 192.168.1.10 # โ
# Validate before reloading
named-checkzone example.com /etc/bind/zones/example.com.zone # โ
# Use CNAME only for aliases, never at the apex
ftp IN CNAME www # โ
โ Don’t Do This:
# Omit the trailing dot on FQDNs
@ IN NS ns1.example.com # Becomes ns1.example.com.example.com. # โ
# Forget to increment the serial
# Secondary servers will not transfer the update # โ
# Place a CNAME at the apex
@ IN CNAME www # Conflicts with NS, MX, SOA # โ
# Use a serial that decreases
2025010201 โ 2025010101 # Secondary ignores the update # โ
# Skip validation before reload
rndc reload # Syntax error causes zone to fail to load # โ
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| Hostname resolves to wrong name | Missing trailing dot | Append . to FQDNs |
| Secondary does not update | Serial not incremented | Increment serial on every change |
| Zone fails to load | CNAME at apex or syntax error | Remove CNAME; run named-checkzone |
| Reverse lookup fails | PTR record missing or zone not configured | Add PTR; configure reverse zone |
| MX not working | Missing trailing dot on mail server | mail.example.com. |
| Negative answers not cached | Minimum field too low | Increase to 300โ3600 |
Real-World Examples
1. SOA record
@ IN SOA ns1.example.com. admin.example.com. ( 2025010101 3600 900 604800 300 )
2. NS records
@ IN NS ns1.example.com.
@ IN NS ns2.example.com.
3. Glue record
ns1 IN A 192.168.1.10
4. Apex A record
@ IN A 192.168.1.20
5. CNAME alias
ftp IN CNAME www
6. MX record
@ IN MX 10 mail.example.com.
7. SPF TXT record
@ IN TXT "v=spf1 ip4:192.168.1.25 -all"
8. PTR record
20 IN PTR www.example.com.
9. AAAA record
www IN AAAA 2001:db8::20
10. Validate zone
named-checkzone example.com /etc/bind/zones/example.com.zone
Visual
Zone File Structure
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ZONE FILE RECORD ORDER โ
โ โ
โ $TTL 86400 โ Default TTL for all records โ
โ โ
โ @ IN SOA ... โ Mandatory; first record โ
โ โโโ serial โ Must increase on change โ
โ โโโ refresh โ Secondary poll interval โ
โ โโโ retry โ Retry interval โ
โ โโโ expire โ Stop answering if no contact โ
โ โโโ minimum โ Negative cache TTL โ
โ โ
โ @ IN NS ... โ Name servers (at least one) โ
โ ns1 IN A ... โ Glue for in-zone name servers โ
โ โ
โ @ IN A ... โ Apex address โ
โ www IN A ... โ Host addresses โ
โ www IN AAAA ... โ IPv6 addresses โ
โ ftp IN CNAME www โ Aliases โ
โ โ
โ @ IN MX 10 mail... โ Mail exchanger โ
โ @ IN TXT "v=spf1..." โ SPF policy โ
โ _dmarc IN TXT "..." โ DMARC policy โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The Trailing Dot
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ RELATIVE VS ABSOLUTE NAMES โ
โ โ
โ Zone origin: example.com. โ
โ โ
โ ns1 โ ns1.example.com. (relative) โ
โ ns1.example.com โ ns1.example.com.example.com. (WRONG) โ
โ ns1.example.com. โ ns1.example.com. (absolute) โ
โ โ
โ Rule: every fully qualified name must end with a dot. โ
โ The dot tells BIND the name is complete; without it, โ
โ BIND appends the zone origin. โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
SOA Timing Relationships
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ refresh, retry, expire, minimum โ
โ โ
โ Primary Secondary โ
โ โโโโโโโโโโโ โโโโโโโโโโโ โ
โ โ Serial โโโโ refresh โโโโโโโโโโโ Serial โ โ
โ โ 2025... โ โ 2025... โ โ
โ โโโโโโโโโโโ โโโโโโโโโโโ โ
โ โ โ โ
โ โ If refresh fails: โ โ
โ โ wait retry seconds โ โ
โ โ try again โ โ
โ โ โ โ
โ โ If no contact for expire: โ โ
โ โ secondary stops answering โ โ
โ โ โ โ
โ โ minimum controls how long โ โ
โ โ NXDOMAIN is cached โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Summary
| Item | Value |
|---|---|
| Mandatory record | SOA (first in file) |
| SOA serial | Must increase on every change |
| SOA refresh | Secondary poll interval |
| SOA retry | Retry interval after failure |
| SOA expire | Stop answering if no contact |
| SOA minimum | Negative cache TTL |
| Name server | NS record (at least one) |
| IPv4 address | A record |
| IPv6 address | AAAA record |
| Alias | CNAME (never at apex) |
MX record (priority + FQDN) | |
| Text policy | TXT record (SPF, DMARC) |
| Reverse | PTR record in in-addr.arpa zone |
| Validation | named-checkzone <zone> <file> |
Key takeaways:
- Every FQDN in a zone file must end with a dot. Without it, BIND appends the zone origin again, producing a name like
ns1.example.com.example.com.that does not exist . - The SOA serial must increase on every change. Secondary servers compare serials to decide whether to transfer. A serial that stays the same or decreases prevents the secondary from updating .
- The SOA timing fields control secondary behavior.
refreshis how often the secondary polls,retryis how long it waits after a failure,expireis when it stops answering if it cannot reach the primary, andminimumis the negative caching TTL . CNAMErecords cannot coexist with other records. The apex must haveAorAAAArecords, not aCNAME, because it already hasNS,SOA, and possiblyMXandTXTrecords .- Glue records break the circular dependency. When a name server is inside the zone it serves, its
Arecord must be in the zone file so resolvers can reach it without first resolving its name. - Validate before reloading.
named-checkzonereports syntax errors and missing records before the zone is loaded. A zone that fails to load produces a server that appears running but refuses queries for that zone.
Remember: A zone file is the authoritative data for a domain. The SOA record declares the zone’s identity and timing. The NS records declare the name servers. The A and AAAA records declare host addresses. The CNAME records declare aliases. The MX and TXT records declare mail and policy. Every fully qualified name ends with a dot, the serial increases on every edit, and the file is validated before it is loaded. A zone file that parses is not necessarily correct; a zone file that answers queries correctly is the goal.
Stop using slow, ad-bloated tool sites! ๐คฎ
๐ Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
โ
Finance (Mortgage, Interest, Inflation)
โ
Tech (Base64, JSON, Dev Suite, IP)
โ
Health (BMI, BMR, TDEE)
โ
Productivity (Timer, Workspace, QR)
โก๏ธ Fast & Private
๐ No data leaves your device
๐ 100% Free
๐ Use it now: https://tools.kandz.me
๐ Bookmark itโyouโll need it later!