Skip to content

published 2022-10-03, updated 2023-09-10


Public Authoritative DNS with BIND on OpenBSD

Running authoritive nameservers for a few zones isn't a complicate or expensive thing to do. This guide will get you through the basic steps to setup a high availability pair of two nameservers using BIND on OpenBSD - complete with forward and reverse mapping zones.

The configuration shown here is pretty much what I've set up to provide domain name services for the zones jkdata.de (forward mapping) and 8.0.7.2.c.7.6.0.1.0.0.2.ip6.arpa (reverse mapping for the IPv6 prefixes 2001:67c:2708::/48 and below).

Assumptions

Requirements & Costs

In total I spend about 6 EUR per month for this setup.

Here's the domain-object for my personal /48 from the RIPE database:

domain:          8.0.7.2.c.7.6.0.1.0.0.2.ip6.arpa
nserver:         dns01.jkdata.de
nserver:         dns02.jkdata.de
admin-c:         JA9284-RIPE
tech-c:          JA9284-RIPE
zone-c:          JA9284-RIPE
mnt-by:          jkdata-de-mnt
created:         2022-11-13T22:18:40Z
last-modified:   2022-11-13T22:18:40Z
source:          RIPE

BIND (named) on OpenBSD

OpenBSD runs BIND in a chroot environment with /var/named/ as its root directory. Log messages are sent to /var/log/daemon. This is the default directory structure:

/var/named/
/var/named/etc/
/var/named/var/
/var/named/tmp/

Conventionally these are the directories people create for zonefiles:

/var/named/master/    // directory for handcrafted zonefiles on your master
/var/named/slaves/    // directory for generated zonefiles on your slave

A working BIND configurarion consists of the zonefiles you need for your use-case and a named.conf that glues everything together, here namely:

The filenames for zonefiles are arbitrary. I prefer to just name them after the zones they are representing.

Primary nameserver (master)

Install bind from OpenBSD's repositories:

dns01# pkg_add isc-bind

Create master directory for zonefiles:

dns01# mkdir /var/named/master

Zonefiles

A zone file is simply a text file that describes a DNS zone; e.g. a sub-domain and its resources (records). See Wikipedia's article on zone files for a brief overview, syntax and example records.

jkdata.de

File: dns01:/var/named/master/jkdata.de

$ORIGIN .
$TTL 86400          ; 1 day
jkdata.de           IN SOA  dns01.jkdata.de. jkdata.posteo.de. (
                            2022100702 ; serial
			    10800      ; refresh (3 hours)
			    3600       ; retry (1 hour
			    604800     ; expire (1 week)
			    86400      ; minimum (1 day)
			    )
                    NS      dns01.jkdata.de.
		    NS      dns02.jkdata.de.
		    A       185.199.108.153
		    A       185.199.109.153
		    A       185.199.110.153
		    A       185.199.111.153
		    AAAA    2606:50c0:8000:0000:0000:0000:0000:0153
		    AAAA    2606:50c0:8001:0000:0000:0000:0000:0153
		    AAAA    2606:50c0:8002:0000:0000:0000:0000:0153
		    AAAA    2606:50c0:8003:0000:0000:0000:0000:0153

$ORIGIN jkdata.de.
dns01                   A       185.16.61.168
                        AAAA    2a03:4000:000a:02fc:0000:0000:0000:0001
dns02                   A       37.120.168.12
                        AAAA    2a03:4000:0006:5049:0000:0000:0000:0001
www                     CNAME   jlsksr.github.io.

8.0.7.2.c.7.6.0.1.0.0.2.ip6.arpa

Reverse mapping for prefix: 2001:67c:2708::/48

File: dns01:/var/named/master/8.0.7.2.c.7.6.0.1.0.0.2.ip6.arpa

$TTL 86400 ; 1 day @ IN SOA dns01.jkdata.de. jkdata.posteo.de. ( 2022112201 ; serial 10800 ; refresh (3 hours) 3600 ; retry (1 hour) 604800 ; expire (1 week) 86400 ; minimum (1 day) ) IN NS dns01.jkdata.de. IN NS dns02.jkdata.de.

; IPv6 PTR entries
$ORIGIN 8.0.7.2.c.7.6.0.1.0.0.2.ip6.arpa.
1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0    IN PTR    er61.jkdata.de.

a.0.0.0.8.0.7.2.c.7.6.0.1.0.0.2.ip6.arpa

Reverse mapping for prefix: 2001:67c:2708:a::/64

File: dns01:/var/named/master/a.0.0.0.8.0.7.2.c.7.6.0.1.0.0.2.ip6.arpa

$TTL 86400 ; 1 day ; origin added to names not ending with a dot: ; a.0.0.0.8.0.7.2.c.7.6.0.1.0.0.2.ip6.arpa @ IN SOA dns01.jkdata.de. jkdata.posteo.de. ( 2022112201 ; serial 10800 ; refresh (3 hours) 3600 ; retry (1 hour) 604800 ; expire (1 week) 86400 ; minimum (1 day) ) IN NS dns01.jkdata.de. IN NS dns02.jkdata.de.

; IPv6 PTR entries
$ORIGIN a.0.0.0.8.0.7.2.c.7.6.0.1.0.0.2.ip6.arpa.
1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0     IN PTR    er61.jkdata.de.

named.conf for master

File: dns01:/var/named/etc/named.conf

acl clients {
    localnets; ::1;
};

acl jka_dns_servers {
    185.16.61.168; 2a03:4000:a:2fc::1;
    37.120.168.12; 2a03:4000:6:5049::1;
};

options {
    directory "/tmp";
    version "";
    listen-on    { any; };
    listen-on-v6 { any; };
    empty-zones-enable yes;
    allow-recursion { clients; };
    dnssec-enable yes;
    dnssec-validation yes;
};

zone "jkdata.de" IN { type master; file "../master/jkdata.de"; allow-transfer { jka_dns_servers; }; };
zone "8.0.7.2.c.7.6.0.1.0.0.2.ip6.arpa" IN { type master; file "../master/8.0.7.2.c.7.6.0.1.0.0.2.ip6.arpa"; allow-transfer { jka_dns_servers; }; };
zone "a.0.0.0.8.0.7.2.c.7.6.0.1.0.0.2.ip6.arpa" IN { type master; file "../master/a.0.0.0.8.0.7.2.c.7.6.0.1.0.0.2.ip6.arpa"; allow-transfer { jka_dns_servers; }; };

Secondary nameserver (slave)

Setting up a slave nameserver basically works like setting up a primary one; A nameserver can be slave for some zones and master for others. The role is set in the zone statements within the named.conf file. Zonefiles are not to be created manually on slaves - they are generated as a result of successful zone-transfers.

Install bind from OpenBSD's repositories:

dns02# pkg_add isc-bind

Create slaves directory for zonefiles and chown it to _bind:

dns02# mkdir /var/named/slaves
dns02# chown _bind:_bind /var/named/slaves

named.conf for slave

File: dns02:/var/named/etc/named.conf

acl clients {
    localnets; ::1;
};

masters jka_dns_masters {
    185.16.61.168; 2a03:4000:a:2fc::1;
};

options {
    directory "/tmp";
    version "";
    listen-on    { any; };
    listen-on-v6 { any; };
    empty-zones-enable yes;
    allow-recursion { clients; };
    dnssec-enable yes;
    dnssec-validation yes;
};

zone "jkdata.de" IN { type slave; file "../slaves/jkdata.de"; masters{ jka_dns_masters; }; allow-transfer { none; }; };
zone "8.0.7.2.c.7.6.0.1.0.0.2.ip6.arpa" IN { type slave; file "../slaves/8.0.7.2.c.7.6.0.1.0.0.2.ip6.arpa"; masters{ jka_dns_masters; };  allow-transfer { none; }; };
zone "a.0.0.0.8.0.7.2.c.7.6.0.1.0.0.2.ip6.arpa" IN { type slave; file "../slaves/a.0.0.0.8.0.7.2.c.7.6.0.1.0.0.2.ip6.arpa"; masters{ jka_dns_masters; };  allow-transfer { none; }; };

Verification

forward

$ ping er61.jkdata.de
PING er61.jkdata.de(er61.jkdata.de (2001:67c:2708:a::1)) 56 data bytes
64 bytes from er61.jkdata.de (2001:67c:2708:a::1): icmp_seq=1 ttl=58 time=17.4 ms

reverse

# traceroute --icmp 2001:67c:2708:a::1
traceroute to 2001:67c:2708:a::1 (2001:67c:2708:a::1), 30 hops max, 80 byte packets
 1  2a03:4000:4b::3 (2a03:4000:4b::3)  0.186 ms  0.214 ms  0.211 ms
 2  2a00:11c0:47:3::fa (2a00:11c0:47:3::fa)  0.356 ms  0.429 ms  0.426 ms
 3  2a00:11c0:47:1:47::141 (2a00:11c0:47:1:47::141)  3.452 ms  3.490 ms  3.529 ms
 4  Te0-0-0-0-pr2.FRA.router.colt.net (2001:7f8::201c:0:2)  3.905 ms  3.928 ms  3.926 ms
 5  fe80::2a0:a50f:fc90:c7d2%ens3 (fe80::2a0:a50f:fc90:c7d2%ens3)  10.977 ms  10.991 ms  11.022 ms
 6  2001:920:19d0::77d (2001:920:19d0::77d)  17.066 ms  16.884 ms  16.992 ms
 7  er61.jkdata.de (2001:67c:2708:a::1)  17.234 ms  17.297 ms  17.314 ms

Operation

Additional resources