NAMED.CONF(5)

๐Ÿ’… named.conf(5) โ€” the BIND 9 config file, explained by your favorite Unix bestie ๐Ÿ’…

NAMED.CONF(5) ยท BIND 9 ยท NAMED.CONF(5)

okay so picture this: you open a file called named.conf and suddenly you're the main character of the entire DNS server. that's this page. welcome ๐Ÿซถ


โœจ NAME โœจ

named.conf โ€” the configuration file for named ๐Ÿ’–


๐ŸŽ€ SYNOPSIS ๐ŸŽ€

named.conf

that's it. that's the whole synopsis. iconic, honestly ๐Ÿ‘‘


๐ŸŒธ DESCRIPTION ๐ŸŒธ

named.conf is the configuration file for named <#std-iscman-named>. like, if named is the server, this file is its whole personality โœจ

bestie heads up: for the complete documentation about all the configuration statements, please refer to the Configuration Reference section in the BIND 9 Administrator Reference Manual. this page is the tour, not the whole museum ๐Ÿ’…

๐Ÿฆ‹ the rules of the vibe ๐Ÿฆ‹

statements are enclosed in braces { } and terminated with a semi-colon ;. clauses inside those statements are also semi-colon terminated. no exceptions, no cap, the semicolon is the moment, the semicolon is the whole point. periodt.

the usual comment styles are supported, all three of them, choose your fighter:

  • C style: /* */
  • C++ style: // to end of line
  • Unix style: # to end of line

โญ the grammar, in all its glory โญ

this is the actual shape of the statements. it's giving very structured, very demure, very "learn the syntax or cry" ๐Ÿ˜ญ โ€” read it slowly, it's a lot, but you've got this:

       acl <string> { <address_match_element>; ... }; // may occur multiple times

       controls {
            inet ( <ipv4_address> | <ipv6_address> | * ) [ port ( <integer> | * ) ] allow { <address_match_element>; ... } [ keys { <string>; ... } ] [ read-only <boolean> ]; // may occur multiple times
            unix <quoted_string> perm <integer> owner <integer> group <integer> [ keys { <string>; ... } ] [ read-only <boolean> ]; // may occur multiple times
       }; // may occur multiple times

       dlz <string> {
            database <string>;
            search <boolean>;
       }; // may occur multiple times

       dnssec-policy <string> {
            cdnskey <boolean>;
            cds-digest-types { <string>; ... };
            dnskey-ttl <duration>;
            inline-signing <boolean>;
            keys { ( csk | ksk | zsk ) [ key-directory | key-store <string> ] lifetime <duration_or_unlimited> algorithm <string> [ tag-range <integer> <integer> ] [ <integer> ]; ... };
            manual-mode <boolean>;
            max-zone-ttl <duration>;
            nsec3param [ iterations <integer> ] [ optout <boolean> ] [ salt-length <integer> ];
            offline-ksk <boolean>;
            parent-ds-ttl <duration>;
            parent-propagation-delay <duration>;
            publish-safety <duration>;
            purge-keys <duration>;
            retire-safety <duration>;
            signatures-jitter <duration>;
            signatures-refresh <duration>;
            signatures-validity <duration>;
            signatures-validity-dnskey <duration>;
            zone-propagation-delay <duration>;
       }; // may occur multiple times

       dyndb <string> <quoted_string> { <unspecified-text> }; // may occur multiple times

       http <string> {
            endpoints { <quoted_string>; ... };
            listener-clients <integer>;
            streams-per-connection <integer>;
       }; // may occur multiple times

       key <string> {
            algorithm <string>;
            secret <string>;
       }; // may occur multiple times

       key-store <string> {
            directory <string>;
            pkcs11-uri <quoted_string>;
       }; // may occur multiple times

       logging {
            category <string> { <string>; ... }; // may occur multiple times
            channel <string> {
                 buffered <boolean>;
                 file <quoted_string> [ versions ( unlimited | <integer> ) ] [ size <size> ] [ suffix ( increment | timestamp ) ];
                 null;
                 print-category <boolean>;
                 print-severity <boolean>;
                 print-time ( iso8601 | iso8601-utc | local | <boolean> );
                 severity <log_severity>;
                 stderr;
                 syslog [ <syslog_facility> ];
            }; // may occur multiple times
       };

       managed-keys { <string> ( static-key | initial-key | static-ds | initial-ds ) <integer> <integer> <integer> <quoted_string>; ... }; // may occur multiple times, deprecated
๐Ÿ’€ real talk: see that managed-keys one at the bottom? it's flagged deprecated. it's still there, it still parses, but it is absolutely giving "please stop using me" energy. don't build anything new on it, bestie. ๐Ÿ™ˆ

and that's the grammar for this part โ€” the statement tour keeps going, so stay with me ๐Ÿ’–โœจ

okay okay okay, deep breath bestie ๐Ÿซถ this is options. the big one. it is long โ€” like, "scroll until your thumb hurts" long โ€” so i'm breaking the grammar up into snack-sized chunks instead of dropping two hundred lines on you at once. you're welcome ๐Ÿ’…

three things to clock before we dive in:

  • it's alphabetical. bless whoever did that, genuinely iconic of them.
  • a lot of these end in { <address_match_element>; ... } โ€” that's the address-match-list family, they all roll together.
  • some lines have a tiny whispered comment at the very end: // may occur multiple times, // deprecated, // obsolete, // test only, // not configured, // experimental. those are not decoration, they're the page telling you something real, so i'll be pointing at them every time ๐Ÿ‘€

starting at the top, the allow-* family ๐Ÿ’– thirteen of them, all in a row:

options {
     allow-new-zones <boolean>;
     allow-notify { <address_match_element>; ... };
     allow-proxy { <address_match_element>; ... }; // experimental
     allow-proxy-on { <address_match_element>; ... }; // experimental
     allow-query { <address_match_element>; ... };
     allow-query-cache { <address_match_element>; ... };
     allow-query-cache-on { <address_match_element>; ... };
     allow-query-on { <address_match_element>; ... };
     allow-recursion { <address_match_element>; ... };
     allow-recursion-on { <address_match_element>; ... };
     allow-transfer [ port <integer> ] [ transport <string> ] { <address_match_element>; ... };
     allow-update { <address_match_element>; ... };
     allow-update-forwarding { <address_match_element>; ... };

see how most of them take { <address_match_element>; ... }? the two little exceptions to that vibe are allow-new-zones, which just wants a plain <boolean>, and allow-transfer, which sneaks in [ port <integer> ] and [ transport <string> ] before its braces. and both allow-proxy and allow-proxy-on are stamped // experimental โ€” noted, bestie ๐Ÿซก


next up, also-notify being the wordiest line we've seen so far, followed by a little aโ€“b stretch:

     also-notify [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
     answer-cookie <boolean>;
     attach-cache <string>;
     auth-nxdomain <boolean>;
     automatic-interface-scan <boolean>;
     avoid-v4-udp-ports { <portrange>; ... }; // deprecated
     avoid-v6-udp-ports { <portrange>; ... }; // deprecated
     bindkeys-file <quoted_string>; // test only
     blackhole { <address_match_element>; ... };

that also-notify line is giving main character energy โ€” it's got [ port <integer> ], [ source ], [ source-v6 ], and then a whole server list where each entry can carry its own [ key <string> ] and [ tls <string> ]. meanwhile avoid-v4-udp-ports and avoid-v6-udp-ports are both marked // deprecated ๐Ÿ˜ญ and bindkeys-file is // test only, so don't get attached.


the check-* crew plus that absolute unit catalog-zones:

     catalog-zones { zone <string> [ default-primaries [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... } ] [ zone-directory <quoted_string> ] [ in-memory <boolean> ] [ min-update-interval <duration> ]; ... };
     check-dup-records ( fail | warn | ignore );
     check-integrity <boolean>;
     check-mx ( fail | warn | ignore );
     check-mx-cname ( fail | warn | ignore );
     check-names ( primary | master | secondary | slave | response ) ( fail | warn | ignore ); // may occur multiple times
     check-sibling <boolean>;
     check-spf ( warn | ignore );
     check-srv-cname ( fail | warn | ignore );
     check-svcb <boolean>;
     check-wildcard <boolean>;

catalog-zones is literally the longest line on this page so far โ€” it's got zone <string>, an optional default-primaries that reuses that whole server-list syntax from also-notify, zone-directory <quoted_string>, in-memory <boolean>, and min-update-interval <duration>, all wrapped up with a ; ... meaning you can stack them. and peep that check-names takes two parenthesised groups โ€” ( primary | master | secondary | slave | response ) and then ( fail | warn | ignore ) โ€” plus it's // may occur multiple times. fancy โœจ


the cโ€“d stretch, where the disable-* trio all say hi:

     clients-per-query <integer>;
     cookie-algorithm ( siphash24 );
     cookie-secret <string>; // may occur multiple times
     deny-answer-addresses { <address_match_element>; ... } [ except-from { <string>; ... } ];
     deny-answer-aliases { <string>; ... } [ except-from { <string>; ... } ];
     dialup ( notify | notify-passive | passive | refresh | <boolean> ); // deprecated
     directory <quoted_string>;
     disable-algorithms <string> { <string>; ... }; // may occur multiple times
     disable-ds-digests <string> { <string>; ... }; // may occur multiple times
     disable-empty-zone <string>; // may occur multiple times

cookie-algorithm only has one value in it right now, siphash24, and that's not me being lazy, that's genuinely the whole list. dialup is wearing a // deprecated sticker ๐Ÿฅฒ and the three disable-* lines plus cookie-secret are all // may occur multiple times, meaning yes, you can absolutely put more than one.


okay, dns64 โ€” one of the few here that actually opens a brace and has its own little sub-options (the other one is coming way later, don't worry):

     dns64 <netprefix> {
          break-dnssec <boolean>;
          clients { <address_match_element>; ... };
          exclude { <address_match_element>; ... };
          mapped { <address_match_element>; ... };
          recursive-only <boolean>;
          suffix <ipv6_address>;
     }; // may occur multiple times
     dns64-contact <string>;
     dns64-server <string>;
     dnskey-sig-validity <integer>; // obsolete
     dnsrps-enable <boolean>; // not configured
     dnsrps-library <quoted_string>; // not configured
     dnsrps-options { <unspecified-text> }; // not configured
     dnssec-accept-expired <boolean>;
     dnssec-dnskey-kskonly <boolean>; // obsolete
     dnssec-loadkeys-interval <integer>;
     dnssec-must-be-secure <string> <boolean>; // may occur multiple times, deprecated
     dnssec-policy <string>;
     dnssec-secure-to-insecure <boolean>; // obsolete
     dnssec-update-mode ( maintain | no-resign ); // obsolete
     dnssec-validation ( yes | no | auto );

count the warning labels with me ๐Ÿ”ฅ dnskey-sig-validity is // obsolete, dnssec-dnskey-kskonly is // obsolete, dnssec-secure-to-insecure is // obsolete, dnssec-update-mode is // obsolete โ€” that's a lot of obsolete, be careful. dnssec-must-be-secure gets the double stamp: // may occur multiple times, deprecated. and the dnsrps-* trio are all // not configured. also note dnssec-update-mode has exactly two values, maintain and no-resign, and dnssec-validation has three, yes, no, auto.


the dnstap quartet and friends, then a straight run to forwarders:

     dnstap { ( all | auth | client | forwarder | resolver | update ) [ ( query | response ) ]; ... }; // not configured
     dnstap-identity ( <quoted_string> | none | hostname ); // not configured
     dnstap-output ( file | unix ) <quoted_string> [ size ( unlimited | <size> ) ] [ versions ( unlimited | <integer> ) ] [ suffix ( increment | timestamp ) ]; // not configured
     dnstap-version ( <quoted_string> | none ); // not configured
     dual-stack-servers [ port <integer> ] { ( <quoted_string> [ port <integer> ] | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ); ... };
     dump-file <quoted_string>;
     edns-udp-size <integer>;
     empty-contact <string>;
     empty-server <string>;
     empty-zones-enable <boolean>;
     fetch-quota-params <integer> <fixedpoint> <fixedpoint> <fixedpoint>;
     fetches-per-server <integer> [ ( drop | fail ) ];
     fetches-per-zone <integer> [ ( drop | fail ) ];
     flush-zones-on-shutdown <boolean>;
     forward ( first | only );
     forwarders [ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]; ... };

every single dnstap* line is // not configured, no exceptions ๐Ÿ’€ dnstap-output is lowkey stacked though โ€” ( file | unix ) <quoted_string> then optional [ size ( unlimited | <size> ) ], [ versions ( unlimited | <integer> ) ], and [ suffix ( increment | timestamp ) ]. fetch-quota-params is the only one here taking four arguments in a row: <integer> and then three <fixedpoint>s. and forward is only ever first or only, that's it.


the fstrm-* wall, then gโ€“i:

     fstrm-set-buffer-hint <integer>; // not configured
     fstrm-set-flush-timeout <integer>; // not configured
     fstrm-set-input-queue-size <integer>; // not configured
     fstrm-set-output-notify-threshold <integer>; // not configured
     fstrm-set-output-queue-model ( mpsc | spsc ); // not configured
     fstrm-set-output-queue-size <integer>; // not configured
     fstrm-set-reopen-interval <duration>; // not configured
     geoip-directory ( <quoted_string> | none );
     heartbeat-interval <integer>; // deprecated
     hostname ( <quoted_string> | none );
     http-listener-clients <integer>;
     http-port <integer>;
     http-streams-per-connection <integer>;
     https-port <integer>;
     interface-interval <duration>;
     ipv4only-contact <string>;
     ipv4only-enable <boolean>;
     ipv4only-server <string>;
     ixfr-from-differences ( primary | master | secondary | slave | <boolean> );

seven fstrm-* options, seven // not configured tags, that's a perfect streak ๐ŸŒˆ and fstrm-set-output-queue-model is the only one of them not taking an <integer> or <duration> โ€” it wants ( mpsc | spsc ). heartbeat-interval is // deprecated (sorry). ixfr-from-differences mirrors check-names energy with ( primary | master | secondary | slave | <boolean> ) โ€” and yes, that <boolean> is in with the keywords, not separate.


the kโ€“m run. watch out, listen-on and listen-on-v6 are here:

     keep-response-order { <address_match_element>; ... }; // obsolete
     key-directory <quoted_string>;
     lame-ttl <duration>;
     listen-on [ port <integer> ] [ proxy <string> ] [ tls <string> ] [ http <string> ] { <address_match_element>; ... }; // may occur multiple times
     listen-on-v6 [ port <integer> ] [ proxy <string> ] [ tls <string> ] [ http <string> ] { <address_match_element>; ... }; // may occur multiple times
     lmdb-mapsize <sizeval>;
     managed-keys-directory <quoted_string>;
     masterfile-format ( raw | text );
     masterfile-style ( full | relative );
     match-mapped-addresses <boolean>;

keep-response-order is // obsolete ๐Ÿชฆ but listen-on and listen-on-v6 are the moment โ€” both take [ port <integer> ] [ proxy <string> ] [ tls <string> ] [ http <string> ] before their address list, and both are // may occur multiple times so you can have as many as you want. also note masterfile-format is only raw or text, and masterfile-style only full or relative โ€” tiny closed sets, no improvising.


okay the max-* avalanche, part one ๐Ÿ’€๐Ÿ’€ this is where the alphabet really commits:

     max-cache-size ( default | unlimited | <sizeval> | <percentage> );
     max-cache-ttl <duration>;
     max-clients-per-query <integer>;
     max-ixfr-ratio ( unlimited | <percentage> );
     max-journal-size ( default | unlimited | <sizeval> );
     max-ncache-ttl <duration>;
     max-query-count <integer>;
     max-query-restarts <integer>;
     max-records <integer>;
     max-records-per-type <integer>;
     max-recursion-depth <integer>;
     max-recursion-queries <integer>;
     max-refresh-time <integer>;
     max-retry-time <integer>;
     max-rsa-exponent-size <integer>;
     max-stale-ttl <duration>;

notice how the types are all over the place โ€” some want <integer>, some <duration>, and then max-cache-size has four choices ( default | unlimited | <sizeval> | <percentage> ), max-ixfr-ratio has ( unlimited | <percentage> ), and max-journal-size has ( default | unlimited | <sizeval> ). read carefully, don't just assume they all take a number, that's how you get got ๐Ÿ™ˆ


max-* part two, cooling down into min-* and multi-master:

     max-transfer-idle-in <integer>;
     max-transfer-idle-out <integer>;
     max-transfer-time-in <integer>;
     max-transfer-time-out <integer>;
     max-types-per-name <integer>;
     max-udp-size <integer>;
     max-validation-failures-per-fetch <integer>; // experimental
     max-validations-per-fetch <integer>; // experimental
     max-zone-ttl ( unlimited | <duration> ); // deprecated
     memstatistics <boolean>;
     memstatistics-file <quoted_string>;
     message-compression <boolean>;
     min-cache-ttl <duration>;
     min-ncache-ttl <duration>;
     min-refresh-time <integer>;
     min-retry-time <integer>;
     min-transfer-rate-in <integer> <integer>;
     minimal-any <boolean>;
     minimal-responses ( no-auth | no-auth-recursive | <boolean> );
     multi-master <boolean>;

max-validation-failures-per-fetch and max-validations-per-fetch are both // experimental (they're lowkey twins, don't mix them up), max-zone-ttl is // deprecated with values ( unlimited | <duration> ), and min-transfer-rate-in is the only min-* here that wants two <integer>s. also minimal-responses โ€” ( no-auth | no-auth-recursive | <boolean> ), that <boolean> sits right in there with the keywords.


the nโ€“q stretch, including the second big braced block of this whole list:

     new-zones-directory <quoted_string>;
     no-case-compress { <address_match_element>; ... };
     nocookie-udp-size <integer>;
     notify ( explicit | master-only | primary-only | <boolean> );
     notify-defer <integer>;
     notify-delay <integer>;
     notify-rate <integer>;
     notify-source ( <ipv4_address> | * );
     notify-source-v6 ( <ipv6_address> | * );
     notify-to-soa <boolean>;
     nsec3-test-zone <boolean>; // test only
     nta-lifetime <duration>;
     nta-recheck <duration>;
     nxdomain-redirect <string>;
     parental-source ( <ipv4_address> | * );
     parental-source-v6 ( <ipv6_address> | * );
     pid-file ( <quoted_string> | none );
     port <integer>;
     preferred-glue <string>;
     prefetch <integer> [ <integer> ];
     provide-ixfr <boolean>;
     qname-minimization ( strict | relaxed | disabled | off );
     query-source [ address ] ( <ipv4_address> | * | none );
     query-source-v6 [ address ] ( <ipv6_address> | * | none );
     querylog <boolean>;

nsec3-test-zone is // test only ๐Ÿงช and qname-minimization has four values: ( strict | relaxed | disabled | off ) โ€” yes, disabled and off, they're both there, don't @ me. query-source and query-source-v6 both take that literal [ address ] keyword before their paren group, and prefetch is the rare one that takes <integer> and then an optional second [ <integer> ]. also pid-file can be a <quoted_string> or none.


and here's rate-limit, the other one with its own braced body โ€” sixteen sub-options, all at once, slay:

     rate-limit {
          all-per-second <integer>;
          errors-per-second <integer>;
          exempt-clients { <address_match_element>; ... };
          ipv4-prefix-length <integer>;
          ipv6-prefix-length <integer>;
          log-only <boolean>;
          max-table-size <integer>;
          min-table-size <integer>;
          nodata-per-second <integer>;
          nxdomains-per-second <integer>;
          qps-scale <integer>;
          referrals-per-second <integer>;
          responses-per-second <integer>;
          slip <integer>;
          window <integer>;
     };

look at all those -per-second ones โ€” all-per-second, errors-per-second, nodata-per-second, nxdomains-per-second, referrals-per-second, responses-per-second โ€” that's six of them, all <integer>. exempt-clients is the odd one out with { <address_match_element>; ... }, and log-only is the only <boolean> in the whole block. the rest are plain <integer>, plus window <integer> sitting at the bottom.


and the last little run for this part, r-city:

     recursing-file <quoted_string>;
     recursion <boolean>;
     recursive-clients <integer>;
     request-expire <boolean>;
     request-ixfr <boolean>;
     request-nsid <boolean>;
     require-server-cookie <boolean>;
     resolver-query-timeout <integer>;
     resolver-use-dns64 <boolean>;
     response-padding { <address_match_element>; ... } block-size <integer>;

response-padding is the one to look at here โ€” it's { <address_match_element>; ... } followed by block-size <integer>, which is a shape we haven't really seen before in this list, so clock it.

and that's where this part stops โ€” we're still inside the options block, the closing }; hasn't happened yet, and there's plenty more alphabet to get through. keep scrolling, we're nowhere near done ๐Ÿซถ

inside the options block, the grammar keeps spilling out like a notes-app draft that got away from us, and this next stretch is a whole mood. first up, the response-policy monster plus its neighbors โ€” yes, that first line is one single statement, and yes, it's giving ctrl+f energy ๐Ÿ’…

response-policy { zone <string> [ add-soa <boolean> ] [ log <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ policy ( cname | disabled | drop | given | no-op | nodata | nxdomain | passthru | tcp-only <quoted_string> ) ] [ recursive-only <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ] [ ede <string> ]; ... } [ add-soa <boolean> ] [ break-dnssec <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ min-ns-dots <integer> ] [ nsip-wait-recurse <boolean> ] [ nsdname-wait-recurse <boolean> ] [ qname-wait-recurse <boolean> ] [ recursive-only <boolean> ] [ servfail-until-ready <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ] [ dnsrps-enable <boolean> ] [ dnsrps-options { <unspecified-text> } ];
responselog <boolean>;
reuseport <boolean>;
root-key-sentinel <boolean>;
rrset-order { [ class <string> ] [ type <string> ] [ name <quoted_string> ] <string> <string>; ... };
secroots-file <quoted_string>;
send-cookie <boolean>;
serial-query-rate <integer>;
serial-update-method ( date | increment | unixtime );
server-id ( <quoted_string> | none | hostname );
servfail-ttl <duration>;
session-keyalg <string>;
session-keyfile ( <quoted_string> | none );
session-keyname <string>;
sig-signing-nodes <integer>;
sig-signing-signatures <integer>;
sig-signing-type <integer>;
sig-validity-interval <integer> [ <integer> ]; // obsolete
sig0checks-quota <integer>; // experimental
sig0checks-quota-exempt { <address_match_element>; ... }; // experimental
sig0key-checks-limit <integer>;
sig0message-checks-limit <integer>;

okay bestie, quick vibe check on that first block: sig-validity-interval is literally wearing a // obsolete sticker, and sig0checks-quota plus sig0checks-quota-exempt are tagged // experimental. that's not me editorializing โ€” it's right there in the grammar. ๐Ÿซถ

next cluster is the sortlist through tcp-send-buffer run, aka the stale-answer and tcp-knob section:

sortlist { <address_match_element>; ... }; // deprecated
stale-answer-client-timeout ( disabled | off | <integer> );
stale-answer-enable <boolean>;
stale-answer-ttl <duration>;
stale-cache-enable <boolean>;
stale-refresh-time <duration>;
startup-notify-rate <integer>;
statistics-file <quoted_string>;
synth-from-dnssec <boolean>;
tcp-advertised-timeout <integer>;
tcp-clients <integer>;
tcp-idle-timeout <integer>;
tcp-initial-timeout <integer>;
tcp-keepalive-timeout <integer>;
tcp-listen-queue <integer>;
tcp-receive-buffer <integer>;
tcp-reuse-timeout <integer>;
tcp-send-buffer <integer>;

and sortlist has a // deprecated comment, so don't act surprised when you see it. ๐ŸŒธ

then the options block wraps up with the tkey-domain through zone-statistics crew:

tkey-domain <quoted_string>; // obsolete
tkey-gssapi-credential <quoted_string>; // deprecated
tkey-gssapi-keytab <quoted_string>;
tls-port <integer>;
transfer-format ( many-answers | one-answer );
transfer-message-size <integer>;
transfer-source ( <ipv4_address> | * );
transfer-source-v6 ( <ipv6_address> | * );
transfers-in <integer>;
transfers-out <integer>;
transfers-per-ns <integer>;
trust-anchor-telemetry <boolean>;
try-tcp-refresh <boolean>;
udp-receive-buffer <integer>;
udp-send-buffer <integer>;
update-check-ksk <boolean>; // obsolete
update-quota <integer>;
use-v4-udp-ports { <portrange>; ... }; // deprecated
use-v6-udp-ports { <portrange>; ... }; // deprecated
v6-bias <integer>;
validate-except { <string>; ... };
version ( <quoted_string> | none );
zero-no-soa-ttl <boolean>;
zero-no-soa-ttl-cache <boolean>;
zone-statistics ( full | terse | none | <boolean> );
};

that }; right there closes the options block โ€” do not drop it, bestie, or the parser will be giving chaos ๐Ÿ˜ญ

outside options now, plugin is allowed to show up multiple times:

plugin ( query ) <string> [ { <unspecified-text> } ]; // may occur multiple times

then remote-servers, also multiple times, with its whole optional port / source / source-v6 situation:

remote-servers <string> [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... }; // may occur multiple times

server <netprefix> is its own little fandom, and it may occur multiple times:

server <netprefix> {
     bogus <boolean>;
     edns <boolean>;
     edns-udp-size <integer>;
     edns-version <integer>;
     keys <server_key>;
     max-udp-size <integer>;
     notify-source ( <ipv4_address> | * );
     notify-source-v6 ( <ipv6_address> | * );
     padding <integer>;
     provide-ixfr <boolean>;
     query-source [ address ] ( <ipv4_address> | * );
     query-source-v6 [ address ] ( <ipv6_address> | * );
     request-expire <boolean>;
     request-ixfr <boolean>;
     request-nsid <boolean>;
     require-cookie <boolean>;
     send-cookie <boolean>;
     tcp-keepalive <boolean>;
     tcp-only <boolean>;
     transfer-format ( many-answers | one-answer );
     transfer-source ( <ipv4_address> | * );
     transfer-source-v6 ( <ipv6_address> | * );
     transfers <integer>;
}; // may occur multiple times

statistics-channels? also may occur multiple times, and inet inside it may occur multiple times too:

statistics-channels {
     inet ( <ipv4_address> | <ipv6_address> | * ) [ port ( <integer> | * ) ] [ allow { <address_match_element>; ... } ]; // may occur multiple times
}; // may occur multiple times

tls <string> is another multiple-times block with cert/key/cipher energy:

tls <string> {
     ca-file <quoted_string>;
     cert-file <quoted_string>;
     cipher-suites <string>;
     ciphers <string>;
     dhparam-file <quoted_string>;
     key-file <quoted_string>;
     prefer-server-ciphers <boolean>;
     protocols { <string>; ... };
     remote-hostname <quoted_string>;
     session-tickets <boolean>;
}; // may occur multiple times

trust-anchors may occur multiple times, and it's giving key-material menu:

trust-anchors { <string> ( static-key | initial-key | static-ds | initial-ds ) <integer> <integer> <integer> <quoted_string>; ... }; // may occur multiple times

and trusted-keys is also multiple-times but literally tagged deprecated in the grammar, so yeah, that's a thing:

trusted-keys { <string> <integer> <integer> <integer> <quoted_string>; ... }; // may occur multiple times, deprecated
          view <string> [ <class> ] {
               allow-new-zones <boolean>;
               allow-notify { <address_match_element>; ... };
               allow-proxy { <address_match_element>; ... }; // experimental
               allow-proxy-on { <address_match_element>; ... }; // experimental
               allow-query { <address_match_element>; ... };
               allow-query-cache { <address_match_element>; ... };
               allow-query-cache-on { <address_match_element>; ... };
               allow-query-on { <address_match_element>; ... };
               allow-recursion { <address_match_element>; ... };
               allow-recursion-on { <address_match_element>; ... };
               allow-transfer [ port <integer> ] [ transport <string> ] { <address_match_element>; ... };
               allow-update { <address_match_element>; ... };
               allow-update-forwarding { <address_match_element>; ... };
               also-notify [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
               attach-cache <string>;
               auth-nxdomain <boolean>;
               catalog-zones { zone <string> [ default-primaries [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... } ] [ zone-directory <quoted_string> ] [ in-memory <boolean> ] [ min-update-interval <duration> ]; ... };
               check-dup-records ( fail | warn | ignore );
               check-integrity <boolean>;
               check-mx ( fail | warn | ignore );
               check-mx-cname ( fail | warn | ignore );
               check-names ( primary | master | secondary | slave | response ) ( fail | warn | ignore ); // may occur multiple times
               check-sibling <boolean>;
               check-spf ( warn | ignore );
               check-srv-cname ( fail | warn | ignore );
               check-svcb <boolean>;
               check-wildcard <boolean>;
               clients-per-query <integer>;
               deny-answer-addresses { <address_match_element>; ... } [ except-from { <string>; ... } ];
               deny-answer-aliases { <string>; ... } [ except-from { <string>; ... } ];
               dialup ( notify | notify-passive | passive | refresh | <boolean> ); // deprecated
               disable-algorithms <string> { <string>; ... }; // may occur multiple times
               disable-ds-digests <string> { <string>; ... }; // may occur multiple times
               disable-empty-zone <string>; // may occur multiple times
               dlz <string> {
                    database <string>;
                    search <boolean>;
               }; // may occur multiple times
               dns64 <netprefix> {
                    break-dnssec <boolean>;
                    clients { <address_match_element>; ... };
                    exclude { <address_match_element>; ... };
                    mapped { <address_match_element>; ... };
                    recursive-only <boolean>;
                    suffix <ipv6_address>;
               }; // may occur multiple times
               dns64-contact <string>;
               dns64-server <string>;
               dnskey-sig-validity <integer>; // obsolete
               dnsrps-enable <boolean>; // not configured
               dnsrps-options { <unspecified-text> }; // not configured
               dnssec-accept-expired <boolean>;
               dnssec-dnskey-kskonly <boolean>; // obsolete
               dnssec-loadkeys-interval <integer>;
               dnssec-must-be-secure <string> <boolean>; // may occur multiple times, deprecated
               dnssec-policy <string>;
               dnssec-secure-to-insecure <boolean>; // obsolete
               dnssec-update-mode ( maintain | no-resign ); // obsolete
               dnssec-validation ( yes | no | auto );
               dnstap { ( all | auth | client | forwarder | resolver | update ) [ ( query | response ) ]; ... }; // not configured
               dual-stack-servers [ port <integer> ] { ( <quoted_string> [ port <integer> ] | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ); ... };
               dyndb <string> <quoted_string> { <unspecified-text> }; // may occur multiple times
               edns-udp-size <integer>;
               empty-contact <string>;
               empty-server <string>;
               empty-zones-enable <boolean>;
               fetch-quota-params <integer> <fixedpoint> <fixedpoint> <fixedpoint>;
               fetches-per-server <integer> [ ( drop | fail ) ];
               fetches-per-zone <integer> [ ( drop | fail ) ];
               forward ( first | only );
               forwarders [ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]; ... };
               ipv4only-contact <string>;
               ipv4only-enable <boolean>;
               ipv4only-server <string>;
               ixfr-from-differences ( primary | master | secondary | slave | <boolean> );
               key <string> {
                    algorithm <string>;
                    secret <string>;
               }; // may occur multiple times
               key-directory <quoted_string>;
               lame-ttl <duration>;
               lmdb-mapsize <sizeval>;
               managed-keys { <string> ( static-key | initial-key | static-ds | initial-ds ) <integer> <integer> <integer> <quoted_string>; ... }; // may occur multiple times, deprecated
               masterfile-format ( raw | text );
               masterfile-style ( full | relative );
               match-clients { <address_match_element>; ... };
               match-destinations { <address_match_element>; ... };
               match-recursive-only <boolean>;
               max-cache-size ( default | unlimited | <sizeval> | <percentage> );
               max-cache-ttl <duration>;
               max-clients-per-query <integer>;
               max-ixfr-ratio ( unlimited | <percentage> );
               max-journal-size ( default | unlimited | <sizeval> );
               max-ncache-ttl <duration>;
               max-query-count <integer>;
               max-query-restarts <integer>;
               max-records <integer>;
               max-records-per-type <integer>;
               max-recursion-depth <integer>;
               max-recursion-queries <integer>;
               max-refresh-time <integer>;
               max-retry-time <integer>;
               max-stale-ttl <duration>;
               max-transfer-idle-in <integer>;
               max-transfer-idle-out <integer>;
               max-transfer-time-in <integer>;
               max-transfer-time-out <integer>;
               max-types-per-name <integer>;
               max-udp-size <integer>;
               max-validation-failures-per-fetch <integer>; // experimental
               max-validations-per-fetch <integer>; // experimental
               max-zone-ttl ( unlimited | <duration> ); // deprecated
               message-compression <boolean>;
               min-cache-ttl <duration>;
               min-ncache-ttl <duration>;
               min-refresh-time <integer>;
               min-retry-time <integer>;
               min-transfer-rate-in <integer> <integer>;
               minimal-any <boolean>;
               minimal-responses ( no-auth | no-auth-recursive | <boolean> );
               multi-master <boolean>;
               new-zones-directory <quoted_string>;
               no-case-compress { <address_match_element>; ... };
               nocookie-udp-size <integer>;
               notify ( explicit | master-only | primary-only | <boolean> );
               notify-defer <integer>;
               notify-delay <integer>;
               notify-source ( <ipv4_address> | * );
               notify-source-v6 ( <ipv6_address> | * );
               notify-to-soa <boolean>;
               nsec3-test-zone <boolean>; // test only
               nta-lifetime <duration>;
               nta-recheck <duration>;
               nxdomain-redirect <string>;
               parental-source ( <ipv4_address> | * );
               parental-source-v6 ( <ipv6_address> | * );
               plugin ( query ) <string> [ { <unspecified-text> } ]; // may occur multiple times
               preferred-glue <string>;
               prefetch <integer> [ <integer> ];
               provide-ixfr <boolean>;
               qname-minimization ( strict | relaxed | disabled | off );
               query-source [ address ] ( <ipv4_address> | * | none );
               query-source-v6 [ address ] ( <ipv6_address> | * | none );
               rate-limit {
                    all-per-second <integer>;
                    errors-per-second <integer>;
                    exempt-clients { <address_match_element>; ... };
                    ipv4-prefix-length <integer>;
                    ipv6-prefix-length <integer>;
                    log-only <boolean>;
                    max-table-size <integer>;
                    min-table-size <integer>;
                    nodata-per-second <integer>;
                    nxdomains-per-second <integer>;
                    qps-scale <integer>;
                    referrals-per-second <integer>;
                    responses-per-second <integer>;
                    slip <integer>;
                    window <integer>;
               };
               recursion <boolean>;
               request-expire <boolean>;
               request-ixfr <boolean>;
               request-nsid <boolean>;
               require-server-cookie <boolean>;
               resolver-query-timeout <integer>;
               resolver-use-dns64 <boolean>;
               response-padding { <address_match_element>; ... } block-size <integer>;
               response-policy { zone <string> [ add-soa <boolean> ] [ log <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ policy ( cname | disabled | drop | given | no-op | nodata | nxdomain | passthru | tcp-only <quoted_string> ) ] [ recursive-only <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ] [ ede <string> ]; ... } [ add-soa <boolean> ] [ break-dnssec <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ min-ns-dots <integer> ] [ nsip-wait-recurse <boolean> ] [ nsdname-wait-recurse <boolean> ] [ qname-wait-recurse <boolean> ] [ recursive-only <boolean> ] [ servfail-until-ready <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ] [ dnsrps-enable <boolean> ] [ dnsrps-options { <unspecified-text> } ];
               root-key-sentinel <boolean>;
               rrset-order { [ class <string> ] [ type <string> ] [ name <quoted_string> ] <string> <string>; ... };
               send-cookie <boolean>;
               serial-update-method ( date | increment | unixtime );
               server <netprefix> {
                    bogus <boolean>;
                    edns <boolean>;
                    edns-udp-size <integer>;
                    edns-version <integer>;
                    keys <server_key>;
                    max-udp-size <integer>;
                    notify-source ( <ipv4_address> | * );
                    notify-source-v6 ( <ipv6_address> | * );
                    padding <integer>;
                    provide-ixfr <boolean>;
                    query-source [ address ] ( <ipv4_address> | * );
                    query-source-v6 [ address ] ( <ipv6_address> | * );
                    request-expire <boolean>;
                    request-ixfr <boolean>;
                    request-nsid <boolean>;
                    require-cookie <boolean>;
                    send-cookie <boolean>;
                    tcp-keepalive <boolean>;

okay so that's the view block and bestie it is HUGE โ€” like, it's giving "I contain multitudes" energy ๐Ÿ˜ญ this is the main character of the whole config file, the one with the lore, the backstory, the questionable exes (looking at you, every line tagged // deprecated).

quick vibe check on the little tags you keep seeing at the end of lines, because they are not decoration:

  • // may occur multiple times โ€” you can drop this one in more than once. Yes, more than once. Slay.
  • // deprecated โ€” it still exists, it still parses, but it's so 2014. Use it and the config gods will side-eye you.
  • // obsolete โ€” bestie, it's a museum piece. It's there, it's documented, don't build your life on it.
  • // experimental โ€” handle with care, it might change on you. Situationship behaviour fr fr.
  • // not configured โ€” it appears in the grammar but it's not actually wired up in this build. It's an NPC.
  • // test only โ€” self-explanatory, it's a lab rat ๐Ÿงช

and pls notice the families in there, because once you see them you can't unsee them:

  • the allow-* girlies: allow-notify, allow-query, allow-query-cache, allow-query-cache-on, allow-query-on, allow-recursion, allow-recursion-on, allow-transfer, allow-update, allow-update-forwarding, plus allow-new-zones and the two <span>experimental</span> ones, allow-proxy and allow-proxy-on โ€” and so many of them take { <address_match_element>; ... } lists.
  • the check-* squad: check-dup-records, check-integrity, check-mx, check-mx-cname, check-names, check-sibling, check-spf, check-srv-cname, check-svcb, check-wildcard. Most of them go ( fail | warn | ignore ) โ€” pick your toxic trait ๐Ÿ’€
  • the max-* / min-* alphabet mafia. There are. So many. max-cache-size, max-records-per-type, max-recursion-depth, max-transfer-idle-in, min-transfer-rate-in <integer> <integer>, minimal-responses ( no-auth | no-auth-recursive | <boolean> )โ€ฆ you get it.
  • the dnssec-* corner and the dns64 block, which is its very own little sub-block with break-dnssec, clients, exclude, mapped, recursive-only, suffix, and can // may occur multiple times.
  • the rate-limit block โ€” that's the full nested set, all the way from all-per-second to window, and yes slip <integer> is in there and no it's not about shoes ๐Ÿฉด
  • response-policy which is like three statements wearing a trenchcoat: a zone <string> list where each zone can carry add-soa, log, max-policy-ttl, min-update-interval, policy ( cname | disabled | drop | given | no-op | nodata | nxdomain | passthru | tcp-only <quoted_string> ), recursive-only, nsip-enable, nsdname-enable, edeโ€ฆ and then the whole thing also takes a pile of its own trailing options like break-dnssec, min-ns-dots, nsip-wait-recurse, nsdname-wait-recurse, qname-wait-recurse, servfail-until-ready, dnsrps-enable, dnsrps-options. iconic, exhausting, love her ๐Ÿ’…
  • rrset-order which is the shortest fanciest one: { [ class <string> ] [ type <string> ] [ name <quoted_string> ] <string> <string>; ... }
  • and then server <netprefix> โ€” the block that starts at the very bottom and, plot twist, keeps going past the end of this chunk. We'll pick it up next, don't worry ๐Ÿซถ
also real talk: all those <angle_bracket_thingies> are placeholders ok, you don't literally type <integer> into your config unless you want the parser to have a bad time ๐Ÿ™ˆ

and yeah, you clocked it โ€” view <string> [ <class> ] { means the whole pile above lives inside a view, and the class bit is optional. you're doing amazing sweetie โœจ

okay so weโ€™re still inside the syntax scroll, bestie, and this is the rest of that block โ€” comments and all, no cap ๐Ÿซถโœจ

                    tcp-only <boolean>;
                    transfer-format ( many-answers | one-answer );
                    transfer-source ( <ipv4_address> | * );
                    transfer-source-v6 ( <ipv6_address> | * );
                    transfers <integer>;
               }; // may occur multiple times
               servfail-ttl <duration>;
               sig-signing-nodes <integer>;
               sig-signing-signatures <integer>;
               sig-signing-type <integer>;
               sig-validity-interval <integer> [ <integer> ]; // obsolete
               sig0key-checks-limit <integer>;
               sig0message-checks-limit <integer>;
               sortlist { <address_match_element>; ... }; // deprecated
               stale-answer-client-timeout ( disabled | off | <integer> );
               stale-answer-enable <boolean>;
               stale-answer-ttl <duration>;
               stale-cache-enable <boolean>;
               stale-refresh-time <duration>;
               synth-from-dnssec <boolean>;
               transfer-format ( many-answers | one-answer );
               transfer-source ( <ipv4_address> | * );
               transfer-source-v6 ( <ipv6_address> | * );
               trust-anchor-telemetry <boolean>;
               trust-anchors { <string> ( static-key | initial-key | static-ds | initial-ds ) <integer> <integer> <integer> <quoted_string>; ... }; // may occur multiple times
               trusted-keys { <string> <integer> <integer> <integer> <quoted_string>; ... }; // may occur multiple times, deprecated
               try-tcp-refresh <boolean>;
               update-check-ksk <boolean>; // obsolete
               v6-bias <integer>;
               validate-except { <string>; ... };
               zero-no-soa-ttl <boolean>;
               zero-no-soa-ttl-cache <boolean>;
               zone-statistics ( full | terse | none | <boolean> );
          }; // may occur multiple times

and yes โ€” the page literally says: โ€œAny of these zone statements can also be set inside the view statement.โ€ so these zone-level statements can also live inside view, iykyk ๐Ÿ’…

then the type primary zone grammar pulls up like:

          zone <string> [ <class> ] {
               type primary;
               allow-query { <address_match_element>; ... };
               allow-query-on { <address_match_element>; ... };
               allow-transfer [ port <integer> ] [ transport <string> ] { <address_match_element>; ... };
               allow-update { <address_match_element>; ... };
               also-notify [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
               check-dup-records ( fail | warn | ignore );
               check-integrity <boolean>;
               check-mx ( fail | warn | ignore );
               check-mx-cname ( fail | warn | ignore );
               check-names ( fail | warn | ignore );
               check-sibling <boolean>;
               check-spf ( warn | ignore );
               check-srv-cname ( fail | warn | ignore );
               check-svcb <boolean>;
               check-wildcard <boolean>;
               checkds ( explicit | <boolean> );
               database <string>;
               dialup ( notify | notify-passive | passive | refresh | <boolean> ); // deprecated
               dlz <string>;
               dnskey-sig-validity <integer>; // obsolete
               dnssec-dnskey-kskonly <boolean>; // obsolete
               dnssec-loadkeys-interval <integer>;
               dnssec-policy <string>;
               dnssec-secure-to-insecure <boolean>; // obsolete
               dnssec-update-mode ( maintain | no-resign ); // obsolete
               file <quoted_string>;
               forward ( first | only );
               forwarders [ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]; ... };
               inline-signing <boolean>;
               ixfr-from-differences <boolean>;
               journal <quoted_string>;
               key-directory <quoted_string>;
               masterfile-format ( raw | text );
               masterfile-style ( full | relative );
               max-ixfr-ratio ( unlimited | <percentage> );
               max-journal-size ( default | unlimited | <sizeval> );
               max-records <integer>;
               max-records-per-type <integer>;
               max-transfer-idle-out <integer>;
               max-transfer-time-out <integer>;
               max-types-per-name <integer>;
               max-zone-ttl ( unlimited | <duration> ); // deprecated
               notify ( explicit | master-only | primary-only | <boolean> );
               notify-defer <integer>;
               notify-delay <integer>;
               notify-source ( <ipv4_address> | * );
               notify-source-v6 ( <ipv6_address> | * );
               notify-to-soa <boolean>;
               nsec3-test-zone <boolean>; // test only
               parental-agents [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
               parental-source ( <ipv4_address> | * );
               parental-source-v6 ( <ipv6_address> | * );
               serial-update-method ( date | increment | unixtime );
               sig-signing-nodes <integer>;
               sig-signing-signatures <integer>;
               sig-signing-type <integer>;
               sig-validity-interval <integer> [ <integer> ]; // obsolete
               update-check-ksk <boolean>; // obsolete
               update-policy ( local | { ( deny | grant ) <string> ( 6to4-self | external | krb5-self | krb5-selfsub | krb5-subdomain | krb5-subdomain-self-rhs | ms-self | ms-selfsub | ms-subdomain | ms-subdomain-self-rhs | name | self | selfsub | selfwild | subdomain | tcp-self | wildcard | zonesub ) [ <string> ] <rrtypelist>; ... } );
               zero-no-soa-ttl <boolean>;
               zone-statistics ( full | terse | none | <boolean> );
          };

lowkey donโ€™t skip the // deprecated, // obsolete, and // test only tags โ€” theyโ€™re literally part of the grammar vibe check ๐Ÿ‘€๐Ÿ’€

and the type secondary zone grammar is here too, with all the extra min/max/transfer bits:

          zone <string> [ <class> ] {
               type secondary;
               allow-notify { <address_match_element>; ... };
               allow-query { <address_match_element>; ... };
               allow-query-on { <address_match_element>; ... };
               allow-transfer [ port <integer> ] [ transport <string> ] { <address_match_element>; ... };
               allow-update-forwarding { <address_match_element>; ... };
               also-notify [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
               check-names ( fail | warn | ignore );
               checkds ( explicit | <boolean> );
               database <string>;
               dialup ( notify | notify-passive | passive | refresh | <boolean> ); // deprecated
               dlz <string>;
               dnskey-sig-validity <integer>; // obsolete
               dnssec-dnskey-kskonly <boolean>; // obsolete
               dnssec-loadkeys-interval <integer>;
               dnssec-policy <string>;
               dnssec-update-mode ( maintain | no-resign ); // obsolete
               file <quoted_string>;
               forward ( first | only );
               forwarders [ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]; ... };
               inline-signing <boolean>;
               ixfr-from-differences <boolean>;
               journal <quoted_string>;
               key-directory <quoted_string>;
               masterfile-format ( raw | text );
               masterfile-style ( full | relative );
               max-ixfr-ratio ( unlimited | <percentage> );
               max-journal-size ( default | unlimited | <sizeval> );
               max-records <integer>;
               max-records-per-type <integer>;
               max-refresh-time <integer>;
               max-retry-time <integer>;
               max-transfer-idle-in <integer>;
               max-transfer-idle-out <integer>;
               max-transfer-time-in <integer>;
               max-transfer-time-out <integer>;
               max-types-per-name <integer>;
               min-refresh-time <integer>;
               min-retry-time <integer>;
               min-transfer-rate-in <integer> <integer>;
               multi-master <boolean>;
               notify ( explicit | master-only | primary-only | <boolean> );
               notify-defer <integer>;
               notify-delay <integer>;
               notify-source ( <ipv4_address> | * );
               notify-source-v6 ( <ipv6_address> | * );
               notify-to-soa <boolean>;
               nsec3-test-zone <boolean>; // test only
               parental-agents [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
               parental-source ( <ipv4_address> | * );
               parental-source-v6 ( <ipv6_address> | * );
               primaries [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
               request-expire <boolean>;
               request-ixfr <boolean>;
               sig-signing-nodes <integer>;
               sig-signing-signatures <integer>;
               sig-signing-type <integer>;
               sig-validity-interval <integer> [ <integer> ]; // obsolete
               transfer-source ( <ipv4_address> | * );
               transfer-source-v6 ( <ipv6_address> | * );
               try-tcp-refresh <boolean>;
               update-check-ksk <boolean>; // obsolete
               zero-no-soa-ttl <boolean>;
               zone-statistics ( full | terse | none | <boolean> );
          };

still more syntax coming in the next chunk, so keep scrolling ๐ŸŒˆ๐Ÿ’œ

Last one of the mirror-family menagerie โ€” the mirror zone is like, the backup dancer of zones. It's read-only, it gets its content from the cache, and ngl it's got opinions:

          zone <string> [ <class> ] {
               type mirror;
               allow-notify { <address_match_element>; ... };
               allow-query { <address_match_element>; ... };
               allow-query-on { <address_match_element>; ... };
               allow-transfer [ port <integer> ] [ transport <string> ] { <address_match_element>; ... };
               allow-update-forwarding { <address_match_element>; ... };
               also-notify [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
               check-names ( fail | warn | ignore );
               database <string>;
               file <quoted_string>;
               ixfr-from-differences <boolean>;
               journal <quoted_string>;
               masterfile-format ( raw | text );
               masterfile-style ( full | relative );
               max-ixfr-ratio ( unlimited | <percentage> );
               max-journal-size ( default | unlimited | <sizeval> );
               max-records <integer>;
               max-records-per-type <integer>;
               max-refresh-time <integer>;
               max-retry-time <integer>;
               max-transfer-idle-in <integer>;
               max-transfer-idle-out <integer>;
               max-transfer-time-in <integer>;
               max-transfer-time-out <integer>;
               max-types-per-name <integer>;
               min-refresh-time <integer>;
               min-retry-time <integer>;
               min-transfer-rate-in <integer> <integer>;
               multi-master <boolean>;
               notify ( explicit | master-only | primary-only | <boolean> );
               notify-defer <integer>;
               notify-delay <integer>;
               notify-source ( <ipv4_address> | * );
               notify-source-v6 ( <ipv6_address> | * );
               primaries [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
               request-expire <boolean>;
               request-ixfr <boolean>;
               transfer-source ( <ipv4_address> | * );
               transfer-source-v6 ( <ipv6_address> | * );
               try-tcp-refresh <boolean>;
               zero-no-soa-ttl <boolean>;
               zone-statistics ( full | terse | none | <boolean> );
          };

โœจ Okay so next up: the forward zone, aka the "idk where that is, ask them" zone. It doesn't hold records, it just forwards. Very delegation-core of it:

          zone <string> [ <class> ] {
               type forward;
               forward ( first | only );
               forwarders [ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]; ... };
          };

Then the hint zone โ€” tiny, humble, mostly just exists for the root hints. Short king ๐Ÿ‘‘:

          zone <string> [ <class> ] {
               type hint;
               check-names ( fail | warn | ignore );
               file <quoted_string>;
          };

And the redirect zone โ€” it's giving "one zone to rule them all", redirecting queries that would otherwise land on a locally-served name:

          zone <string> [ <class> ] {
               type redirect;
               allow-query { <address_match_element>; ... };
               allow-query-on { <address_match_element>; ... };
               dlz <string>;
               file <quoted_string>;
               masterfile-format ( raw | text );
               masterfile-style ( full | relative );
               max-records <integer>;
               max-records-per-type <integer>;
               max-types-per-name <integer>;
               max-zone-ttl ( unlimited | <duration> ); // deprecated
               primaries [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
               zone-statistics ( full | terse | none | <boolean> );
          };
๐Ÿšฉ bestie heads up: max-zone-ttl in the redirect zone is marked deprecated right there in the config block. Do with that information what you will, but likeโ€ฆ don't build your whole personality on it.

The static-stub zone โ€” you're hard-coding the addresses/names of the servers instead of asking around. Iconic, controlling, valid:

          zone <string> [ <class> ] {
               type static-stub;
               allow-query { <address_match_element>; ... };
               allow-query-on { <address_match_element>; ... };
               forward ( first | only );
               forwarders [ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]; ... };
               max-records <integer>;
               max-records-per-type <integer>;
               max-types-per-name <integer>;
               server-addresses { ( <ipv4_address> | <ipv6_address> ); ... };
               server-names { <string>; ... };
               zone-statistics ( full | terse | none | <boolean> );
          };

The stub zone โ€” the og "I only need the NS records from over there, thanks bestie" zone:

          zone <string> [ <class> ] {
               type stub;
               allow-query { <address_match_element>; ... };
               allow-query-on { <address_match_element>; ... };
               check-names ( fail | warn | ignore );
               database <string>;
               dialup ( notify | notify-passive | passive | refresh | <boolean> ); // deprecated
               file <quoted_string>;
               forward ( first | only );
               forwarders [ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]; ... };
               masterfile-format ( raw | text );
               masterfile-style ( full | relative );
               max-records <integer>;
               max-records-per-type <integer>;
               max-refresh-time <integer>;
               max-retry-time <integer>;
               max-transfer-idle-in <integer>;
               max-transfer-time-in <integer>;
               max-types-per-name <integer>;
               min-refresh-time <integer>;
               min-retry-time <integer>;
               min-transfer-rate-in <integer> <integer>;
               multi-master <boolean>;
               primaries [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
               transfer-source ( <ipv4_address> | * );
               transfer-source-v6 ( <ipv6_address> | * );
               zone-statistics ( full | terse | none | <boolean> );
          };
โš ๏ธ also deprecated in here: dialup. It's still documented, it's still real, but it's old news. Respect its history, don't make it your personality.

And finally โ€” the "no thoughts, just vibes" zone. It has no type at all, because it's literally just pointing at another view. The way that a whole zone can be one line ๐Ÿ˜ญ:

          zone <string> [ <class> ] {
               in-view <string>;
          };

๐Ÿ“ FILES ๐Ÿ“

  • /etc/bind/named.conf

That's the file, bestie. That's where the magic lives.


๐Ÿ‘€ SEE ALSO ๐Ÿ‘€

Go read these, they're the supporting cast and they ate:

๐Ÿ’ก fr fr, peep named-checkconf(8) before you reload. It's the vibe check your config file desperately needs.

โœ๏ธ Author โœ๏ธ

Internet Systems Consortium


2026, Internet Systems Consortium


๐ŸŒธ okay that's the whole page, bestie, you made it to the end!! ๐ŸŽ€ This edition is 9.20.30, dated 2026-10-12, page NAMED.CONF(5) โ€” go forth and configure responsibly, mwah ๐Ÿ’…โœจ๐Ÿฆ‹

๐Ÿ“ฆ where this page comes from