(install-dns)= # Domain Name Service (DNS) Domain Name Service (DNS) is an Internet service that maps IP addresses and {term}`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 {term}`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 allow 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 {term}`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/).