The domain name system (DNS) resolves hostnames (e.g. www.example.net) to IP addresses.
BIND is the most used DNS server on the internet.
Originally, this tutorial was written to show how to configure a subdomain
in BIND 9 on Debian 10 (buster). It was extended with DNS over TLS (DoT) and
how to block domains (e.g. ad servers) with BIND 9 on Debian 13 (trixie).
The official Debian repository includes BIND 9:
apt install bind9
To run a name server for a subdomain sub.example.net,
the following records are relevant in the zone of the domain example.net:
sub IN NS ns1.sub.example.net. ; name server for subdomain sub.example.net
ns1.sub IN A 192.0.2.1 ; IPv4 address of ns1.sub.example.net
ns1.sub IN AAAA 2001:db8:10::1 ; IPv6 address of ns1.sub.example.net
The DNS server ns1.sub.example.net needs to accept incoming packages
on the following ports:
The zone file for sub.example.net needs to be specified in the configuration file:
/etc/bind/named.conf.localzone "sub.example.net" {
type master;
file "/var/lib/bind/db.sub.example.net";
};
The zone file defines records for a (sub)domain.
Here is an exemplary zone file for the subdomain sub.example.net:
/var/lib/bind/db.sub.example.net$TTL 86400
@ IN SOA ns1.sub.example.net. root.example.net. (
2020042301 ; Serial (YYYYMMDDxx)
3600 ; Refresh (1 hour)
600 ; Retry (10 mins)
604800 ; Expire (7 days)
1800 ) ; Negative Cache TTL (30 mins)
@ IN NS ns1.sub.example.net.
ns1 IN A 192.0.2.1
ns1 IN AAAA 2001:db8:10::1
; other hostnames
somehost IN A 192.0.2.10
another IN A 192.0.2.11
The content of the exemplary zone file means the following:
@" is an alias for the zone itself (sub.example.net).ns1.sub.example.net for the subdomain sub.example.net isThe following command reloads the configuration:
rndc reload
Install the dnsutils package:
apt install dnsutils
Verify that the DNS lookup returns the correct IP address:
nslookup somehost.sub.example.net
Updating the DNS records is useful when IP addresses are dynamically assigned.
For instance, DHCP servers automatically assign IP addresses to hosts.
The following command generates a random rndc key and
prints a configuration example to the terminal:
rndc-confgen
To allow a client to update the DNS records of sub.example.net with an rndc key,
enable it in the configuration file:
/etc/bind/named.conf.localinclude "/etc/bind/rndc.key";
zone "sub.example.net" {
type master;
file "/var/lib/bind/db.sub.example.net";
allow-update { key "rndc-key"; };
};
For updating DNS records, the following command line tool is used:
nsupdate
These commands update the IPv4 address of somehost.sub.example.net:
key rndc-key C3...DQ==
update delete somehost.sub.example.net A
update add somehost.sub.example.net 86400 A 192.0.2.123
send
/etc/bind/named.conf.optionstls mycert {
cert-file "/etc/letsencrypt/live/example.net/fullchain.pem";
key-file "/etc/letsencrypt/live/example.net/privkey.pem";
};
tls google-tls {
ca-file "/etc/ssl/certs/ca-certificates.crt";
remote-hostname "dns.google";
};
tls cloudflare-tls {
ca-file "/etc/ssl/certs/ca-certificates.crt";
remote-hostname "one.one.one.one";
};
options {
directory "/var/cache/bind";
listen-on port 53 { any; };
listen-on-v6 port 53 { any; };
listen-on port 853 tls mycert { any; };
listen-on-v6 port 853 tls mycert { any; };
allow-recursion { any; };
forwarders port 853 {
8.8.8.8 tls google-tls;
8.8.4.4 tls google-tls;
1.1.1.1 tls cloudflare-tls;
1.0.0.1 tls cloudflare-tls;
};
forward only;
};
Add the user bind to the group ssl-cert:
usermod -a -G ssl-cert bind
Configure AppArmor to allow reading the certificates:
/etc/apparmor.d/local/usr.sbin.named# Allow BIND to read Let's Encrypt certificates
/etc/letsencrypt/archive/example.net/* r,
/etc/letsencrypt/live/example.net/* r,
/etc/bind/named.conf.localinclude "/etc/bind/adservers-blacklist.conf";
/etc/bind/adservers-blacklist.confzone "adserver.com" { type master; notify no; file "/etc/bind/blocked.zone"; };
/etc/bind/blocked.zone$TTL 86400
@ IN SOA ns1.example.net. hostmaster.example.net. (
2026102701 ; serial number YYMMDDNN
28800 ; refresh 8 hours
7200 ; retry 2 hours
864000 ; expire 10 days
86400 ) ; min ttl 1 day
@ IN NS ns1.example.net.
@ IN A 127.0.0.1
* IN A 127.0.0.1
wget -q -O - 'https://pgl.yoyo.org/adservers/serverlist.php?hostformat=bindconfig&showintro=0&mimetype=plaintext' \
| sed 's#null.zone.file#/etc/bind/blocked.zone#' \
> /etc/bind/adservers-blacklist.conf