In the early days of Mac OS X Server I setup a local DNS server to satisfy the requirements of Open Directory to help keep my personal files in sync between my MacBook and my Mac Pro, and also supporting a centralised backup strategy for other users; the wonders of iCloud bring similar advantages in modern times. Using an AirPort Extreme base station I was able to push the single DNS server through DHCP to clients and it all worked well. In modern times with IPv6 and a more complex DrayTek router it is not possible to publish a single DNS server, and an ISP name server is pushed via DHCP creating the possibility of an internal address resolution returning with an internet address: this has happened infrequently but enough to cause issues. A secondary internal DNS server is required which will get its records from the existing primary hosted on an HPE ProLiant Microserver with BIND9 on Red Hat Enterprise Linux 10. The Mac mini that serves files with an attached Pegasus32 R4, offers Content Caching and VirtualBox Hypervisor will now serve as the secondary DNS Server.
Prerequisite
The following example works with a BIND9 service running a primary DNS server on Red Hat Enterprise Linux 10 and will use a Mac mini with a recent version of macOS as the secondary. We need:
- A configured and working named instance on Red Hat Enterprise Linux or derivative with a static IPv4 address and IPv6 address: unless you don’t have an IPv6 enabled network. These instructions should give an idea of how to configure a BIND9 instance on other systems with some adaptations.
- A Mac that can be permanently awake and also has fixed IP addresses.
- A macOS major release not older than 3 years; for security updates.
- Router admin access.
Deciding How To Install BIND9
There are 3 ways I know of to get BIND working on macOS: they are:
Compile from source as previously recommended by Apple.- Install from MacPorts.
- From Homebrew (brew.sh)
I will immediately discard the compile from source option since as BIND9 has evolved increasing build dependencies often best resolved by installing packages from MacPorts or Homebrew; and so it makes more sense to install BIND9 through one of these.
You can install BIND9 from either MacPorts or Homebrew but beware that the two package management systems are not designed to work together. Because I use Oracle Cloud Infrastructure I have oci-cli which is installed through Homebrew on the system which is to be my secondary DNS server: this ultimately makes my decision to install BIND9 through Homebrew.
Configure the Mac to Work as a Server
- Open ‘System Settings’ > ‘Privacy & Security’: go down to ‘Security’ and turn off ‘FileVault’ if it is on; FileVault requires that a user logs in with their password on startup or reboot before any services can be loaded which is not convenient for a server.
- From ‘System Settings’ select ‘Energy’ and make sure that the following options are turned on:
- Prevent automatic sleeping when the display is off
- Start up automatically after a power failure
- In ‘System Preferences’ > ‘Energy’ make sure that the option ‘Put hard disks to sleep when possible’ is turned off.
- Make the current IPv6 address permanent by changing the ‘Configure IPv6’ option to ‘Manually’ in the ‘TCP/IP’ section in your network connections ‘Details…’ and take note of the IPv6 address for use later.
If you intend to run the Mac headless be sure to enable ‘Remote Login’ and either ‘Screen Sharing’ or ‘Remote Management’ in ‘System Settings’ > ‘General’ > ‘Sharing’.
Installing BIND9 with Homebrew
Homebrew is run unprivileged but can provide system level services. Always assume commands are run from your admin user account without sudo unless otherwise specified.
- Go to brew.sh then follow instructions to setup the environment then keep your terminal open.
- Now working in the terminal do:
brew install bind - Enable the server with:
sudo brew services start bind
Take note of the advice following the last command relating to files that have to be manually removed if bind is to be upgraded; these directories should not contain your configuration files. Your named.log file will be located at /opt/homebrew/var/log/named (Apple Silicon) or: /usr/local/var/log/named (macOS intel).
Setting Up the Primary
In this example the primary DNS server is hosted on Red Hat Enterprise Linux 10 through the bind package provided. Red Hat have good documentation about configuring zone transfers so this section is similar to their documentation:
- We need to generate a key for the two servers to authenticate each other. This must be done from a root shell so if your system does not have the root account enabled do:
sudo sufollowed by your password. Run the following command to generate the key and add it to /etc/named.conf , copy the output as you will need it later.
tsig-keygen macintosh-rescue-transfer-key | tee -a /etc/named.conf
- Now edit your zone declarations to allow transfer to the secondary. In this example I allow the transfer of two zones: ‘macintosh-rescue.net’ and ‘ha.greenhac.org.uk’ plus a reverse lookup zone.
//forward zone
zone "macintosh-rescue.net" IN {
type master;
file "db.macintosh-rescue.net";
allow-transfer { key macintosh-rescue-transfer-key; };
};
//backward zone
zone "1.0.10.in-addr.arpa" IN {
type master;
file "db.1.0.10.in-addr.arpa";
allow-transfer { key macintosh-rescue-transfer-key; };
};
//forward zone
zone "ha.greenhac.org.uk" IN {
type master;
file "db.ha.greenhac.org.uk";
allow-transfer { key macintosh-rescue-transfer-key; };
};
- We now need to declare our Mac server as a name server in the zones files located at /var/named which has the effect of authorising transfer to the secondary: in the following examples this server has an address of 10.0.1.189 and already has a AAA record for virtualbox.macintosh-rescue.net :
db.macintosh-rescue.net
macintosh-rescue.net. 10800 IN SOA macintosh-rescue.net. admin.macintosh-rescue.net. (
2020073003
3600
900
1209600
86400)
10800 IN NS control.macintosh-rescue.net.
10800 IN NS virtualbox.macintosh-rescue.net.
control.macintosh-rescue.net. 10800 IN A 10.0.1.200
opendirectory.macintosh-rescue.net. 10800 IN A 10.0.1.199
museum.macintosh-rescue.net. 10800 IN A 10.0.1.198
sus.macintosh-rescue.net. 10800 IN A 10.0.1.197
netinstall.macintosh-rescue.net. 10800 IN A 10.0.1.196
virtualbox.macintosh-rescue.net. 10800 IN A 10.0.1.189
windows10.macintosh-rescue.net. 10800 IN A 10.0.1.110
windows11.macintosh-rescue.net. 10800 IN A 10.0.1.111
train.macintosh-rescue.net. 10800 IN A 10.0.1.100
linuxworkstation.macintosh-rescue.net. 10800 IN A 10.0.1.98
macintosh-rescue.net. 10800 IN A 193.123.184.101
*.macintosh-rescue.net. 10800 IN A 193.123.184.101
db.1.0.10.in-addr.arpa
1.0.10.in-addr.arpa. 10800 IN SOA 1.0.10.in-addr.arpa. admin.1.0.10.in-addr.arpa. (
2020073003
3600
900
1209600
86400)
10800 IN NS control.macintosh-rescue.net.
10800 IN NS virtualbox.macintosh-rescue.net.
13.1.0.10.in-addr.arpa. 10800 IN PTR ha.greenhac.org.uk.
98.1.0.10.in-addr.arpa. 10800 IN PTR linuxworkstation.macintosh-rescue.net.
100.1.0.10.in-addr.arpa. 10800 IN PTR train.macintosh-rescue.net.
110.1.0.10.in-addr.arpa. 10800 IN PTR windows10.macintosh-rescue.net.
111.1.0.10.in-addr.arpa. 10800 IN PTR windows11.macintosh-rescue.net.
189.1.0.10.in-addr.arpa. 10800 IN PTR virtualbox.macintosh-rescue.net.
196.1.0.10.in-addr.arpa. 10800 IN PTR netinstall.macintosh-rescue.net.
197.1.0.10.in-addr.arpa. 10800 IN PTR sus.macintosh-rescue.net.
198.1.0.10.in-addr.arpa. 10800 IN PTR museum.macintosh-rescue.net.
199.1.0.10.in-addr.arpa. 10800 IN PTR opendirectory.macintosh-rescue.net.
200.1.0.10.in-addr.arpa. 10800 IN PTR control.macintosh-rescue.net.
db.ha.greenhac.org.uk
ha.greenhac.org.uk. 10800 IN SOA macintosh-rescue.net. admin.macintosh-rescue.net. (
2020073003
3600
900
1209600
86400)
10800 IN NS control.macintosh-rescue.net.
10800 IN NS virtualbox.macintosh-rescue.net.
ha.greenhac.org.uk. 10800 IN A 10.0.1.13
- Now reload named with:
service named reload - Now close your root shell ‘control’ & ‘D’ .
Setting Up the Secondary (The Mac)
We already have a running named service on the Mac not doing anything useful, so now we’ll add a few entries into the named.conf file and prepare to copy the zones from the primary.
Language and Cultural Fail Warning!
We live in a society in which prominent power structures are a consequence of various nations involved in colonialism. In computing the term “slave” is used casually ignoring the horrors concealed behind the meaning of that word. The word slave is required for a configuration file to work in the examples following:
We will first configure some forwarder zones for queries not handled by our internal DNS servers which can aid in internet address resolution performance. I recommend for the purposes of redundancy that the primary and secondary servers use different forwarders so that in the event that a major provider failed you would likely still be able to resolve internet addresses. I am using Cloudflare as a forwarder on one of my servers and my ISP’s on the other.
- Add a forwarding block inside your options block like in the example below:
options {
directory "/usr/local/var/named";
forwarders {
1.1.1.1;
1.0.0.1;
2606:4700:4700::1112;
2606:4700:4700::1002;
};
};
- We now need to declare the key we created for the primary server in the secondaries named.conf file: this is identical to the 4 lines appended to the bottom of the named.conf file on the primary:
key "macintosh-rescue-transfer-key" {
algorithm hmac-sha256;
secret "iamnotpublishingthisontheinternet=";
};
- Now we need to declare the zones that the secondary DNS server will duplicate from the primary
zone "macintosh-rescue.net" {
type slave;
file "secondaries/macintosh-rescue.net.zone";
allow-query { any; };
allow-transfer { none; };
masters {
10.0.1.200 key macintosh-rescue-transfer-key;
2a02:390:575b:1:e68:d9df:f881:396 key macintosh-rescue-transfer-key;
};
};
zone "ha.greenhac.org.uk" {
type slave;
file "secondaries/ha.greenhac.org.uk.zone";
allow-query { any; };
allow-transfer { none; };
masters {
10.0.1.200 key macintosh-rescue-transfer-key;
2a02:390:575b:1:e68:d9df:f881:396 key macintosh-rescue-transfer-key;
};
};
zone "1.0.10.in-addr.arpa" {
type slave;
file "secondaries/1.0.10.in-addr.arpa";
allow-query { any; };
allow-transfer { none; };
masters {
10.0.1.200 key macintosh-rescue-transfer-key;
2a02:390:575b:1:e68:d9df:f881:396 key macintosh-rescue-transfer-key;
};
};
- The named.conf file will define named’s working directory but generally for a Homebrew installation it would be: /opt/homebrew/var/named , and on macOS intel: /usr/local/var/named . create the ‘secondaries’ directory in the path which correlates with your Homebrew installation like:
mkdir /opt/homebrew/var/named/secondaries
- Now reload the service and verify that everything has worked:
sudo brew services reload bind #reload the service
cat /opt/homebrew/var/log/named/named.log #make sure the service loaded OK
ls /opt/homebrew/var/named/secondaries #check that zone files appear
In my case the first time I reloaded the service there was an error about my key. To resolve the error I deleted the key declaration in the named.conf file on my primary server, then repeated the process to generate and append a new key. I then copied the new key declaration and replaced it on the secondaries named.conf file which corrected the error on reload.
Finishing Up
- Access your network router or DHCP servers settings and add your secondary Mac DNS servers IPv4 address into the lan secondary dns server entry, then for DHCPv6 add the Mac servers IPv6 address as the secondary.
- If you ‘Renew DHCP Lease’ in the ‘TCP/IP’ details on your client Mac’s network connection, ‘OK’ ‘Apply’ then load the ‘DNS’ details you should no longer see an external DNS server referenced.
- You can do some test DNS queries with the commands like:
host machine.macintosh-rescue.net primarydnsserverip
host gnome.org primarydnsserverip
host machine.macintosh-rescue.net secondarydnsserverip
host gnome.org secondarydnsserverip
Acknowledgements
My thanks to my cat Merlin for keeping me company whilst figuring this out. My thanks also to my partner Peter (https://greenhac.org.uk) for answering daft questions and generally supporting me through life.