Table of Contents
Introduction
BIND, which stands for Berkeley Internet Name Domain, is one of the most widely used DNS server implementations on Unix-like systems. In practical server administration, BIND is a reference implementation of many DNS standards and is common on traditional Linux DNS servers. In this chapter you will focus on how to set up BIND in a typical Linux environment, from installation to basic configuration and testing. General DNS concepts and record types are discussed in other sections, so here the emphasis is on BIND specific files, configuration patterns, and operational steps.
Installing BIND
On most Linux distributions the BIND server package is called bind9 or named. Installation is done using the system package manager. On Debian or Ubuntu, the main server is installed with a package like bind9 and supporting utilities in packages such as bind9-utils. On Fedora and other RHEL based systems the package is typically called bind with tools in bind-utils.
BIND runs as a system service, usually named named. After installation, the package manager will place the main configuration file in /etc/bind/named.conf on Debian based systems, or in /etc/named.conf on Red Hat based systems. Zone files and additional configuration fragments are usually stored under /var/cache/bind or /var/named depending on the distribution defaults.
Once installed, you enable and start the service using your system service manager. With systemd this is typically systemctl enable named and systemctl start named. If you use a distribution that names the service bind9, the commands adapt accordingly. You verify that the daemon is running and listening on port 53 using standard tools such as ss or netstat, which will show UDP and TCP sockets bound to port 53 on the configured interfaces.
Core BIND Configuration Files
BIND uses a small hierarchy of configuration files that define global options and point to specific zone definitions. The exact paths may differ per distribution, but the structure is conceptually similar.
The main configuration file, often /etc/named.conf or /etc/bind/named.conf, defines the global options block, logging configuration, and a list of zone declarations. On Debian derivatives, the main file may include subfiles such as /etc/bind/named.conf.options, /etc/bind/named.conf.local, and /etc/bind/named.conf.default-zones. On Red Hat based systems, the main file often contains everything in one place, or includes /etc/named.rfc1912.zones for example zone definitions.
A minimal main configuration file has an options block where you specify directory, recursion behavior, listening addresses, and ACLs. It also contains at least one zone statement for each domain or reverse zone that your server is authoritative for. BIND reads its configuration at startup or when it receives a reload signal and will log any syntax errors. Because BIND is strict, even a small typo can prevent the daemon from starting.
You must understand that configuration is hierarchical: global options apply by default, but individual zone blocks can override specific properties. Additionally, ACLs are often defined at the top level and then referenced by name inside other blocks, which avoids repeating IP lists in multiple places.
Basic `options` and ACLs
The options block is central to how BIND behaves as a server. It describes default directories, network bindings, recursion settings, and security related restrictions.
At minimum, you specify the directory for zone files, commonly /var/named or /var/cache/bind, using directory "path";. You specify which interfaces BIND listens on with listen-on { ... }; for IPv4 and listen-on-v6 { ... }; for IPv6. If you want BIND to listen on all interfaces, you use any;, and if you want it to listen only on the loopback interface, you use 127.0.0.1; and ::1;.
You also configure whether recursion is allowed. A recursive resolver will look up answers from other authoritative servers on behalf of clients. An authoritative only server will serve only zones it is responsible for and will not perform external lookups. The directive recursion yes; or recursion no; defines this behavior.
To control who can send recursive queries, you define access control lists, or ACLs. An ACL is declared at the top level with a name and a list of address elements.
For example:
acl "trusted" {
192.0.2.0/24;
198.51.100.10;
localhost;
};
Once defined, this ACL can be used inside options as allow-recursion { trusted; }; and allow-query { any; }; or more restricted combinations. Using ACLs is safer than embedding raw IP addresses throughout the configuration and is an important part of BIND deployment.
Some distributions enable dnssec-validation auto; by default, along with system provided root trust anchors. Unless you specifically need to change DNSSEC behavior, you normally keep that default and instead focus on access control and zone statements.
Never allow unrestricted recursion from the entire internet on a public BIND server. Always restrict recursive queries to trusted networks using ACLs and allow-recursion.
Authoritative Zone Configuration
Authoritative zones are at the core of BIND usage as a DNS server. To make BIND authoritative for a domain, you add a zone statement in the main configuration and associate it with a zone file.
A basic forward zone definition looks like this:
zone "example.com" IN {
type master;
file "example.com.zone";
allow-update { none; };
};
The zone name is the domain. The class IN stands for Internet and is almost always used. The type directive defines the role of this server with respect to that zone. For a primary server that holds the writable copy of the zone data, the type is master. The file path is relative to the directory specified in the global options block unless you use an absolute path.
The allow-update directive controls whether dynamic updates are accepted for this zone. For static zones that you edit by hand, you typically disable updates with allow-update { none; };. For dynamic zones that accept updates from DHCP or other automated systems, you specify appropriate ACLs or keys, which is handled elsewhere in the course.
Once you add a zone, you must create the referenced zone file. A zone file is a text file that contains resource records for the domain. BIND automatically loads and parses the zone file at startup and on reload. Any syntax errors appear in logs and can be diagnosed with validation tools.
In addition to forward zones, you may configure reverse zones for IPv4 and IPv6 addresses. A reverse zone uses a special name under in-addr.arpa for IPv4 and ip6.arpa for IPv6.
Structure of Zone Files
Zone files have a specific syntax that BIND expects. While the details of DNS record types are covered somewhere else, here you need to understand the structural elements that matter for BIND loading and operation.
A zone file begins with a Start of Authority record, abbreviated as SOA. Before that, you often specify a default Time To Live (TTL) using $TTL. The TTL is in seconds and defines how long resolvers can cache records that do not specify their own TTL.
A minimal example:
$TTL 3600
@ IN SOA ns1.example.com. hostmaster.example.com. (
2025010101 ; serial
3600 ; refresh
900 ; retry
604800 ; expire
86400 ; minimum
)
The @ symbol represents the origin, which is the zone name. The SOA record lists the primary nameserver and an email address for the zone administrator, where the @ in the email address is replaced with a dot. The parenthesized numbers are, in order, the serial number, refresh, retry, expire, and minimum TTL values.
Always increment the SOA serial number whenever you change zone data on a master server. Secondary servers rely on the serial to detect changes and keep zones synchronized.
After the SOA, you describe the nameserver records and other resource records. BIND supports both absolute names and relative names. Relative names are appended to the zone origin and are convenient for hostnames inside the zone. When you end a name with a dot, BIND treats it as an absolute domain name and does not append the origin.
You may also see $ORIGIN directives used to temporarily change the origin within a zone file. If you use them, be careful to track where you are in the file because it affects how names are expanded.
Zone files must conform strictly to syntax. BIND provides the named-checkzone utility which reads a zone file and checks it for correctness. Using this tool before reloading the service avoids runtime failures.
Creating a Simple Forward Zone
To illustrate a practical setup, consider a small internal domain example.local served from a master BIND instance. The named.conf contains a zone statement like:
zone "example.local" IN {
type master;
file "example.local.zone";
};
Assume that the directory in options is /var/named. You then create /var/named/example.local.zone owned and writable by the user under which named runs.
A simple zone file could be:
$TTL 3600
@ IN SOA ns1.example.local. admin.example.local. (
2025010801 ; serial
3600 ; refresh
600 ; retry
1209600 ; expire
3600 ; minimum
)
IN NS ns1.example.local.
ns1 IN A 192.0.2.10
www IN A 192.0.2.20
Here, the origin @ is example.local. The NS record points to ns1.example.local as the authoritative nameserver. The ns1 and www host records are relative names, which BIND expands to full names by appending .example.local.
Once this file is in place, you use named-checkzone example.local /var/named/example.local.zone to confirm that it is syntactically correct. After fixing any errors, you reload BIND with rndc reload or by issuing a service reload via systemd.
With the zone loaded, queries for www.example.local to your BIND server will return the configured A record if your server is reachable and configured to answer queries from that client.
Setting Up a Reverse Zone
Reverse zones map IP addresses back to names. BIND treats them as separate zones with their own names. For IPv4, the reverse zone name is formed by reversing the octets of the network part and appending .in-addr.arpa.
For example, suppose you have an internal network 192.0.2.0/24 and you want reverse lookups for that range. The reverse zone name is 2.0.192.in-addr.arpa. In your main configuration you define:
zone "2.0.192.in-addr.arpa" IN {
type master;
file "2.0.192.in-addr.arpa.zone";
};The reverse zone file then associates last octets with hostnames using PTR records:
$TTL 3600
@ IN SOA ns1.example.local. admin.example.local. (
2025010801 ; serial
3600
600
1209600
3600
)
IN NS ns1.example.local.
10 IN PTR ns1.example.local.
20 IN PTR www.example.local.
The relative names 10 and 20 represent the host part of the IP addresses 192.0.2.10 and 192.0.2.20. The PTR records point to fully qualified domain names with trailing dots. When configured, a reverse lookup for 192.0.2.20 uses the in-addr.arpa mechanism and returns www.example.local. if your BIND server is consulted for that zone.
As with forward zones, you validate the reverse zone file with named-checkzone and reload BIND once the file is correct. Consistent forward and reverse mappings are often required by some applications and improve clarity when examining logs and using tools like dig -x.
Master and Slave Configuration
BIND supports the traditional master and slave model for distributing authoritative data. The master holds the writable zone file and acts as the source of truth. Slaves hold read-only copies and keep them synchronized via zone transfers.
On the master server, zones look as previously shown, with type master;. You also define which IP addresses are allowed to perform zone transfers using allow-transfer. You may also list secondary servers explicitly. For example:
zone "example.com" IN {
type master;
file "example.com.zone";
allow-transfer { 198.51.100.53; };
also-notify { 198.51.100.53; };
};
The allow-transfer directive limits AXFR and IXFR transfers to authorized secondaries. The also-notify directive instructs the master to send DNS NOTIFY messages to those IP addresses whenever the zone's serial number changes. This prompts the slaves to check for updates more quickly than waiting for the normal refresh interval.
On the slave server, you configure a corresponding zone with type slave; and specify one or more masters that the slave will contact for zone transfers. For example:
zone "example.com" IN {
type slave;
masters { 192.0.2.10; };
file "slaves/example.com.zone";
};
The file for a slave zone is maintained automatically by BIND and should be in a directory writable by the named process. You do not edit slave zone files manually. When the slave starts or receives a NOTIFY, it queries the master for the SOA record, compares serial numbers, and performs a transfer if needed.
On public authoritative servers, always restrict zone transfers using allow-transfer and, if possible, IP based ACLs. Unrestricted zone transfers can disclose internal hostnames and structure to anyone on the internet.
Running BIND as a Recursive Resolver
Although BIND is widely used for authoritative service, it can also act as a recursive resolver for clients. In this role, BIND responds to any query it receives, possibly by contacting root and other authoritative nameservers on the internet until it finds an answer.
To set up BIND as a recursive resolver only, you define an options block with recursion yes;, restrict recursion to trusted networks, and avoid creating zones that would make it authoritative for public domains unless you intend that. You also typically use forwarders or rely on the root hints.
The forwarders directive lists upstream DNS servers to which BIND will forward queries that it cannot answer locally. For example:
options {
directory "/var/named";
recursion yes;
allow-recursion { trusted; };
listen-on { 127.0.0.1; 192.0.2.1; };
listen-on-v6 { ::1; };
forwarders {
203.0.113.53;
203.0.113.54;
};
forward-only yes;
};
With forward-only yes;, BIND will not attempt to contact authoritative nameservers itself. Instead, it forwards all non-local queries to the specified upstream servers and returns their answers to your clients. If forward-only is omitted, BIND will use the forwarders as a first choice and fall back to full resolution using the root hints if they fail.
Using BIND as a local caching resolver reduces latency for repeated queries and centralizes DNS behavior for your network. When combined with proper ACLs, this setup is a secure way to provide DNS resolution services to your internal clients.
Using `rndc` and Reloading Configuration
BIND includes a remote control tool named rndc which communicates with the named daemon over a local or network control channel. It allows you to reload configuration, reload specific zones, flush caches, and query status without restarting the service.
The rndc configuration is typically located in /etc/rndc.conf or similar, and on modern systems distribution packages often generate keys and control statements automatically. The main BIND configuration includes a controls clause that defines the control port, listening addresses, and keys used by rndc.
Common rndc commands include:
rndc reload which reloads the entire configuration and all zones. This is preferred over restarting the service because it avoids disrupting existing queries.
rndc reload example.com which reloads only the specified zone, useful when you have edited a single zone file and want to test changes quickly.
rndc flush which clears the server cache, important when you want to remove stale records faster than normal TTL expiration.
rndc status which reports version, build options, recently used memory, and uptime of the running named instance.
Before relying on rndc, you should verify that the control channel is configured correctly by trying rndc status. If there are permission or key issues, BIND logs will provide hints on how to fix them.
Security and Chroot Considerations
Exposing a DNS server, especially BIND, to the internet requires careful security configuration. At the BIND layer, you already control recursion and zone transfers. At the operating system layer, you further contain the server process and reduce its attack surface.
Many distributions run BIND in a chroot environment, often installed as /var/named/chroot or similar. In this mode, the named process sees that directory as its root. All configuration files, zone files, and writable directories must then exist inside the chroot. Service scripts and documentation usually indicate whether chroot is enabled and where to place your files. When using chroot, remember that paths in named.conf are relative to the chroot root, not the real system root.
BIND supports running under a dedicated unprivileged user, commonly named or bind, configured in the systemd unit and in some BIND configuration options. This user must have read access to zone files and write access only where necessary, such as dynamic zone directories or journal files.
Firewalls should allow UDP and TCP port 53 to and from the networks that should reach the server. For authoritative only servers, you might only allow queries from anywhere towards your public IP, but for recursive resolvers, you restrict access to internal subnets only.
Additionally, BIND supports various mechanisms like TSIG keys for secure dynamic updates and secure zone transfers. These mechanisms are defined in the BIND configuration with key and server statements and used in allow-update, also-notify, and masters directives. While deep details belong to more advanced sections, you should be aware that secure key based control is preferred over simply trusting source IP addresses.
Regular updates of BIND via the distribution package manager are crucial because DNS software is a frequent target of security research and vulnerabilities. Because BIND is a core system service, you typically schedule maintenance windows when restarting or upgrading it on critical systems.
Testing and Troubleshooting
After configuring and starting BIND, you must verify that it behaves as expected. Validation occurs at two levels: static checks of configuration and zone files and dynamic checks of runtime query behavior.
BIND includes two key static validators. named-checkconf tests the global configuration file syntax. You run it without arguments to check default paths or with a specific configuration file path. It reports the first syntax error it encounters, including line number and a short message. Using this tool before starting or reloading named avoids confusing failures.
named-checkzone validates individual zone files as mentioned. It checks SOA format, NS presence, record syntax, and basic logical consistency. It also reports warnings about common misconfigurations, such as missing terminating dots on fully qualified names where they are expected.
For runtime tests, you use DNS client tools, typically dig or host. To test an authoritative zone from the server itself, you can run:
dig @127.0.0.1 example.com SOA
This directly queries the local server on the loopback interface for the SOA record of example.com. You can test arbitrary record types, including A, AAAA, MX, NS, and PTR. To test reverse zones, dig -x 192.0.2.20 @127.0.0.1 is convenient.
If queries fail, check the BIND logs. With systemd systems, you use journalctl -u named or journalctl -u bind9 to review messages. BIND can also be configured with a dedicated logging channel that writes to files under /var/log. BIND error messages are usually explicit about which file and line caused a problem.
When BIND is not responding at all, ensure that the service is active, that it is listening on the expected interfaces and ports, and that no firewall or SELinux policy is silently blocking queries. On systems with SELinux, you may need to set the relevant booleans or file contexts so that named is allowed to read your zone files and bind to port 53. Distribution documentation provides the exact steps.
By combining careful configuration, strict validation with BIND tools, and systematic query testing with DNS client utilities, you can set up a robust BIND instance that serves as either an authoritative server, a recursive resolver, or a hybrid, depending on your network requirements.