(install-dns)= # Domain Name Service (DNS) Domain Name Service (DNS) is an Internet service that maps IP addresses and fully qualified domain names (FQDN) to one another. In this way, DNS alleviates the need to remember IP addresses. Computers that run DNS are called **name servers**. Ubuntu ships with the Berkley Internet Naming Daemon (BIND), the most common program used for maintaining a name server on Linux. ## Install DNS At a terminal prompt, run the following command to install the `bind9` package: ```bash sudo apt install bind9 ``` A useful package for testing and troubleshooting DNS issues is the `dnsutils` package. Very often these tools will be installed already, but to check and/or install `dnsutils` enter the following: ```bash sudo apt install dnsutils ``` ## DNS configuration overview There are many ways to configure BIND9. Some of the most common configurations include a caching nameserver, primary server, and secondary server. - When configured as a **caching nameserver**, BIND9 will find the answer to name queries and remember the answer when the domain is queried again. - As a **primary server**, BIND9 reads the data for a zone from a file on its host, and is authoritative for that zone. - As a **secondary server**, BIND9 gets the zone data from another nameserver that is authoritative for the zone. ### Configuration files The DNS configuration files are stored in the `/etc/bind` directory. The primary configuration file is `/etc/bind/named.conf`, which in the layout provided by the package just includes these files: - **`/etc/bind/named.conf.options`**: Global DNS options - **`/etc/bind/named.conf.local`**: For your zones - **`/etc/bind/named.conf.default-zones`**: Default zones such as localhost, its reverse, and the root hints The root nameservers used to be described in the file `/etc/bind/db.root`. This is now provided instead by the `/usr/share/dns/root.hints` file shipped with the `dns-root-data` package, and is referenced in the `named.conf.default-zones` configuration file above. It is possible to configure the same server to be a caching name server, primary, and secondary: it all depends on the zones it is serving. A server can be the Start of Authority (SOA) for one zone, while providing secondary service for another zone. All the while providing caching services for hosts on the local LAN. ## Set up a caching nameserver The default configuration acts as a caching server. Simply uncomment and edit `/etc/bind/named.conf.options` to set the IP addresses of your ISP's DNS servers: ``` forwarders { 1.2.3.4; 5.6.7.8; }; ``` > **Note**: > Replace `1.2.3.4` and `5.6.7.8` with the IP addresses of actual nameservers. To enable the new configuration, restart the DNS server. From a terminal prompt, run: ```bash sudo systemctl restart bind9.service ``` [See the dig section](#dig) for information on testing a caching DNS server. ## Set up a primary server In this section BIND9 will be configured as the primary server for the domain `example.com`. You can replace `example.com` with your FQDN (Fully Qualified Domain Name). ### Forward zone file To add a DNS zone to BIND9, turning BIND9 into a primary server, first edit `/etc/bind/named.conf.local`: ``` zone "example.com" { type master; file "/etc/bind/db.example.com"; }; ``` > **Note**: > If BIND will be receiving automatic updates to the file as with DDNS, then use `/var/lib/bind/db.example.com` rather than `/etc/bind/db.example.com` both here and in the copy command below. Now use an existing zone file as a template to create the `/etc/bind/db.example.com` file: ```bash sudo cp /etc/bind/db.local /etc/bind/db.example.com ``` Edit the new zone file `/etc/bind/db.example.com` and change `localhost.` to the FQDN of your server, including the additional `.` at the end. Change `127.0.0.1` to the nameserver's IP address and `root.localhost` to a valid email address, but with a `.` instead of the usual `@` symbol, again including the `.` at the end. Change the comment to indicate the domain that this file is for. Create an **A record** for the base domain, `example.com`. Also, create an **A record** for `ns.example.com`, the name server in this example: ``` ; ; BIND data file for example.com ; $TTL 604800 @ IN SOA example.com. root.example.com. ( 2 ; Serial 604800 ; Refresh 86400 ; Retry 2419200 ; Expire 604800 ) ; Negative Cache TTL @ IN NS ns.example.com. @ IN A 192.168.1.10 @ IN AAAA ::1 ns IN A 192.168.1.10 ``` You must increment the `Serial Number` every time you make changes to the zone file. If you make multiple changes before restarting BIND9, only increment `Serial` once. Now, you can add DNS records to the bottom of the zone file. See {ref}`Common Record Types ` for details. > **Note**: > Many admins like to use the "last edited" date as the Serial of a zone, such as **2020012100** which is **yyyymmddss** (where **ss** is the Serial Number) Once you have made changes to the zone file, BIND9 needs to be restarted for the changes to take effect: ```bash sudo systemctl restart bind9.service ``` ### Reverse zone file Now that the zone is set up and resolving names to IP Addresses, a **reverse zone** needs to be added to allows DNS to resolve an address to a name. Edit `/etc/bind/named.conf.local` and add the following: ``` zone "1.168.192.in-addr.arpa" { type master; file "/etc/bind/db.192"; }; ``` > **Note**: > Replace `1.168.192` with the first three octets of whatever network you are using. Also, name the zone file `/etc/bind/db.192` appropriately. It should match the first octet of your network. Now create the `/etc/bind/db.192` file: ```bash sudo cp /etc/bind/db.127 /etc/bind/db.192 ``` Next edit `/etc/bind/db.192`, changing the same options as `/etc/bind/db.example.com`: ``` ; ; BIND reverse data file for local 192.168.1.XXX net ; $TTL 604800 @ IN SOA ns.example.com. root.example.com. ( 2 ; Serial 604800 ; Refresh 86400 ; Retry 2419200 ; Expire 604800 ) ; Negative Cache TTL ; @ IN NS ns. 10 IN PTR ns.example.com. ``` The `Serial Number` in the reverse zone needs to be incremented on each change as well. For each **A record** you configure in `/etc/bind/db.example.com` that is for a different address, you will need to create a **PTR record** in `/etc/bind/db.192`. After creating the reverse zone file restart BIND9: ```bash sudo systemctl restart bind9.service ``` ## Set up a secondary server Once a primary server has been configured, a **secondary server** is highly recommended. This will maintain the availability of the domain if the primary becomes unavailable. First, on the primary server, the zone transfer needs to be allowed. Add the `allow-transfer` option to the example **Forward** and **Reverse** zone definitions in `/etc/bind/named.conf.local`: ``` zone "example.com" { type master; file "/etc/bind/db.example.com"; allow-transfer { 192.168.1.11; }; }; zone "1.168.192.in-addr.arpa" { type master; file "/etc/bind/db.192"; allow-transfer { 192.168.1.11; }; }; ``` > **Note**: > Replace `192.168.1.11` with the IP address of your secondary nameserver. Restart BIND9 on the primary server: ```bash sudo systemctl restart bind9.service ``` Next, on the secondary server, install the `bind9` package the same way as on the primary. Then edit the `/etc/bind/named.conf.local` and add the following declarations for the Forward and Reverse zones: ``` zone "example.com" { type secondary; file "db.example.com"; masters { 192.168.1.10; }; }; zone "1.168.192.in-addr.arpa" { type secondary; file "db.192"; masters { 192.168.1.10; }; }; ``` Once again, replace `192.168.1.10` with the IP address of your primary nameserver, then restart BIND9 on the secondary server: ```bash sudo systemctl restart bind9.service ``` In `/var/log/syslog` you should see something similar to the following (some lines have been split to fit the format of this document): ```text client 192.168.1.10#39448: received notify for zone '1.168.192.in-addr.arpa' zone 1.168.192.in-addr.arpa/IN: Transfer started. transfer of '100.18.172.in-addr.arpa/IN' from 192.168.1.10#53: connected using 192.168.1.11#37531 zone 1.168.192.in-addr.arpa/IN: transferred serial 5 transfer of '100.18.172.in-addr.arpa/IN' from 192.168.1.10#53: Transfer completed: 1 messages, 6 records, 212 bytes, 0.002 secs (106000 bytes/sec) zone 1.168.192.in-addr.arpa/IN: sending notifies (serial 5) client 192.168.1.10#20329: received notify for zone 'example.com' zone example.com/IN: Transfer started. transfer of 'example.com/IN' from 192.168.1.10#53: connected using 192.168.1.11#38577 zone example.com/IN: transferred serial 5 transfer of 'example.com/IN' from 192.168.1.10#53: Transfer completed: 1 messages, 8 records, 225 bytes, 0.002 secs (112500 bytes/sec) ``` > **Note**: > A zone is only transferred if the `Serial Number` on the primary is larger than the one on the secondary. If you want to have your primary DNS notify other secondary DNS servers of zone changes, you can add `also-notify { ipaddress; };` to `/etc/bind/named.conf.local` as shown in the example below: ``` zone "example.com" { type master; file "/etc/bind/db.example.com"; allow-transfer { 192.168.1.11; }; also-notify { 192.168.1.11; }; }; zone "1.168.192.in-addr.arpa" { type master; file "/etc/bind/db.192"; allow-transfer { 192.168.1.11; }; also-notify { 192.168.1.11; }; }; ``` > **Note**: > The default directory for non-authoritative zone files is `/var/cache/bind/`. This directory is also configured in AppArmor to allow the named daemon to write to it. See this page for {ref}`more information on AppArmor `. ## Testing your setup ### resolv.conf The first step in testing BIND9 is to add the nameserver's IP address to a **hosts resolver**. The Primary nameserver should be configured as well as another host to double check things. Refer to {ref}`DNS client configuration ` for details on adding nameserver addresses to your network clients. In the end your `nameserver` line in `/etc/resolv.conf` should be pointing at `127.0.0.53` and you should have a `search` parameter for your domain. Something like this: ```text nameserver 127.0.0.53 search example.com ``` To check which DNS server your local resolver is using, run: ```bash resolvectl status ``` > **Note**: > You should also add the IP address of the secondary nameserver to your client configuration in case the primary becomes unavailable. ### dig If you installed the `dnsutils` package you can test your setup using the DNS lookup utility `dig`: After installing BIND9 use `dig` against the loopback interface to make sure it is listening on port 53. From a terminal prompt: ```bash dig -x 127.0.0.1 ``` You should see lines similar to the following in the command output: ``` ;; Query time: 1 msec ;; SERVER: 192.168.1.10#53(192.168.1.10) ``` If you have configured BIND9 as a caching nameserver, "dig" an outside domain to check the query time: ```bash dig ubuntu.com ``` Note the query time toward the end of the command output: ``` ;; Query time: 49 msec ``` After a second `dig` there should be improvement: ``` ;; Query time: 1 msec ``` ### ping Now let's demonstrate how applications make use of DNS to resolve a host name, by using the `ping` utility to send an ICMP echo request: ```bash ping example.com ``` This tests if the nameserver can resolve the name `ns.example.com` to an IP address. The command output should resemble: ``` PING ns.example.com (192.168.1.10) 56(84) bytes of data. 64 bytes from 192.168.1.10: icmp_seq=1 ttl=64 time=0.800 ms 64 bytes from 192.168.1.10: icmp_seq=2 ttl=64 time=0.813 ms ``` ### named-checkzone A great way to test your zone files is by using the `named-checkzone` utility installed with the `bind9` package. This utility allows you to make sure the configuration is correct before restarting BIND9 and making the changes live. To test our example forward zone file, enter the following from a command prompt: ```bash named-checkzone example.com /etc/bind/db.example.com ``` If everything is configured correctly you should see output similar to: ``` zone example.com/IN: loaded serial 6 OK ``` Similarly, to test the reverse zone file enter the following: ``` named-checkzone 1.168.192.in-addr.arpa /etc/bind/db.192 ``` The output should be similar to: ``` zone 1.168.192.in-addr.arpa/IN: loaded serial 3 OK ``` > **Note**: > The Serial Number of your zone file will probably be different. ### Quick temporary query logging With the `rndc` tool, you can quickly turn query logging on and off, without restarting the service or changing the configuration file. To turn query logging on, run: ```bash sudo rndc querylog on ``` Likewise, to turn it off, run: ```bash sudo rndc querylog off ``` The logs will be sent to `syslog` and will show up in `/var/log/syslog` by default: ``` Jan 20 19:40:50 new-n1 named[816]: received control channel command 'querylog on' Jan 20 19:40:50 new-n1 named[816]: query logging is now on Jan 20 19:40:57 new-n1 named[816]: client @0x7f48ec101480 192.168.1.10#36139 (ubuntu.com): query: ubuntu.com IN A +E(0)K (192.168.1.10) ``` > **Note**: > The amount of logs generated by enabling `querylog` could be huge! ## Logging BIND9 has a wide variety of logging configuration options available, but the two main ones are **channel** and **category**, which configure where logs go, and what information gets logged, respectively. If no logging options are configured the default configuration is: ``` logging { category default { default_syslog; default_debug; }; category unmatched { null; }; }; ``` Let's instead configure BIND9 to send **debug** messages related to DNS queries to a separate file. We need to configure a **channel** to specify which file to send the messages to, and a **category**. In this example, the category will log all queries. Edit `/etc/bind/named.conf.local` and add the following: ``` logging { channel query.log { file "/var/log/named/query.log"; severity debug 3; }; category queries { query.log; }; }; ``` > **Note**: > The `debug` option can be set from 1 to 3. If a level isn't specified, level 1 is the default. Since the **named daemon** runs as the `bind` user, the `/var/log/named` directory must be created and the ownership changed: ```bash sudo mkdir /var/log/named sudo chown bind:bind /var/log/named ``` Now restart BIND9 for the changes to take effect: ```bash sudo systemctl restart bind9.service ``` You should see the file `/var/log/named/query.log` fill with query information. This is a simple example of the BIND9 logging options. For coverage of advanced options see the "Further Reading" section at the bottom of this page. ## Common record types This section covers some of the most common DNS record types. - **`A` record** This record maps an IP address to a hostname. ``` www IN A 192.168.1.12 ``` - **`CNAME` record** Used to create an alias to an existing A record. You cannot create a `CNAME` record pointing to another `CNAME` record. ``` web IN CNAME www ``` - **`MX` record** Used to define where emails should be sent to. Must point to an `A` record, not a `CNAME`. ``` @ IN MX 1 mail.example.com. mail IN A 192.168.1.13 ``` - **`NS` record** Used to define which servers serve copies of a zone. It must point to an `A` record, not a `CNAME`. This is where primary and secondary servers are defined. ``` @ IN NS ns.example.com. @ IN NS ns2.example.com. ns IN A 192.168.1.10 ns2 IN A 192.168.1.11 ``` ## Further reading - [Upstream BIND9 Documentation](https://bind9.readthedocs.io/en/latest/) - [DNS and BIND](http://shop.oreilly.com/product/9780596100575.do) is a popular book now in its fifth edition. There is now also a [DNS and BIND on IPv6](http://shop.oreilly.com/product/0636920020158.do) book. - A great place to ask for BIND9 assistance, and get involved with the Ubuntu Server community, is the `#ubuntu-server` IRC channel on [Libera Chat](https://libera.chat/).