Installing and setting up named / BIND / DNS Server on OS X

Last update: Mar 01 2016 17:25


This post about setting up BIND on OS X 10.11.3 El Capitan is an update to my rewrite (for Yosemite) of my original post about it (and its updates) from December 7, 2010, back when I was running Mac OS X 10.6.5. The information is in abbreviated form, so some familiarity and comfort about updating your system and development is required. YMMV. TANSTAAFL.


Simply, it makes things faster and often more accurate. Every web site you go to, every domain name inside every web page, all require DNS resolution. A single web page may reference assets on multiple subdomains and domains, each of which also require DNS resolution, e.g.,,,, and,,,, etc. If you aren't running your own nameserver, you are at the mercy of your ISP or someone you've pointed your DNS settings at to do your DNS resolution for you. Their DNS servers may go offline, may hold onto obsolete information, or may simply be slow in responding, which when browsing the web is death by a thousand cuts.

By running your own nameserver, you're in control, and your nameserver can go out and get the answers, removing at least one layer of delay.

In addition to the often dramatic speed increase, you can also create simple zone files for parts of the Internet you'd like to block, such as irresponsible advertising.


Install local copy of OpenSSL

Create a new folder under /usr/local which we'll use to hold a local copy of OpenSSL (we won't touch OS X's install of OpenSSL). Replace myusername below with your login account username.

$ sudo mkdir /usr/local/bindmac
$ whoami

$ sudo chown myusername /usr/local/bindmac
$ mkdir /usr/local/bindmac/openssl
$ cd /usr/local/bindmac/openssl

Get the latest OpenSSL, which at the time of writing was

$ wget

Next, extract the archive, then create a local install directory for when you compile it:

$ tar zxf openssl-1.0.2g.tar.gz
$ mkdir install-1.0.2g

To make things easier for the future, we'll create a symbolic link to an install folder, which we'll refer to during compilation.

$ ln -s install-1.0.2g install

Compile OpenSSL, specifying a prefix so that it installs into our local folder:

$ cd openssl-1.0.2g
$ sudo ./Configure darwin64-x86_64-cc --prefix=/usr/local/bindmac/openssl/install-1.0.2g
$ sudo make depend
$ sudo make
$ sudo make test
$ sudo make install

Install BIND

Create a new folder which we'll use to hold the BIND source code for compilation

$ mkdir /usr/local/bindmac/bind
$ cd /usr/local/bindmac/bind

Get the latest BIND, which at the time of writing was bind-9.10.3-P3.tar.gz, and put it in the folder /usr/local/bindmac/bind

$ tar zxf bind-9.10.3-P3.tar.gz
$ cd bind-9.10.3-P3
$ sudo ./configure --with-openssl=/usr/local/bindmac/openssl/install
$ sudo make
$ sudo make test

At this point the test should fail, which is expected. Next run the script to add some virtual interfaces for doing the tests, and run a force-test. Note: the tests take a long time. Go get a sandwich.

$ sudo bin/tests/system/ up
$ sudo make force-test
$ sudo make install

Configure BIND

Start by going into a root shell. Don't forget to exit your root shell at the end.

$ sudo bash

Next, generate configuration and key files used to administer BIND

$ /usr/local/sbin/rndc-confgen | sed '/^#/d' | head -n 10 > /etc/rndc.conf
$ head -n 4 /etc/rndc.conf > /etc/rndc.key

Next, create a basic /etc/named.conf configuration file for BIND. You can probably get away with using the sample one below, but ideally you should customize this according to your needs.

$ cat > /etc/named.conf  <<'END'
# /etc/named.conf

include "/etc/rndc.key";

// modify to be your non-localhost local network to allow access, or omit the entry
acl our-networks { localhost;; };
acl bogus-networks {;;;;;; };

// control access from the /usr/local/sbin/rndc utility to be this computer only
controls { inet allow {; } keys { "rndc-key"; }; };

// global options
options {
	directory "/var/named";
	allow-new-zones yes;
	notify no;
	querylog yes;
	allow-query { our-networks; };
	allow-recursion { our-networks; };
	allow-transfer { our-networks; };
	blackhole { bogus-networks; };
	max-ncache-ttl 300;
	// If you enable the next two lines (forward... and forwarders...), BIND will query OpenDNS first
	// (for all zones we are not master on) if it does not already have the answer cached.
	// forward first;
	// forwarders {;; };
	// If you want to use Google DNS instead of the line above, use the line below
	// forwarders {;; };

zone "." IN { type hint; file ""; };

zone "localhost" IN { type master; file ""; allow-update { none; }; };

zone "" IN { type master; file "named.local"; allow-update { none; }; };

// local upstream ISP may present internal response different from external queries (e.g. for SMTP/POP/IMAP)
// so defer to them, but fallback if no response from them
zone "" IN { type forward; forward first; forwarders {;; }; };

// When querying for zone, use the OpenDNS name servers. This is an example of per-domain use of OpenDNS
zone "" IN { type forward; forward first; forwarders {;; }; };

// When querying for zone, use the Google name servers. This is an example of per-domain use of Google DNS
zone "" IN { type forward; forward first; forwarders {;; }; };

// include (master) zones for irresponsible advertisers to block them
include "/var/named/named.advert";

// include manually blocked zones
include "/var/named/named.blocked";

// server log configuration
logging {
	category default { log_default; };
	category resolver { log_resolver; }; 
	category client { log_client; };
	category queries { log_queries; };
	category query-errors { log_query-errors; };
	category lame-servers { log_lame; };

	channel log_default { file "/var/log/named/named.log" versions unlimited size 20m; severity info; print-time yes; print-category yes; };
	channel log_resolver { file "/var/log/named/named-res.log" versions 5 size 20m; severity info; print-time yes; };
	channel log_client { file "/var/log/named/named-client.log" versions 5 size 20m; severity info; print-time yes; };
	channel log_queries { file "/var/log/named/named-queries.log" versions 5 size 20m; severity info; print-time yes; };
	channel log_query-errors { file "/var/log/named/named-query-errors.log" versions 5 size 20m; severity info; print-time yes; };
	channel log_lame { file "/var/log/named/named-lame.log" versions 5 size 5m; severity info; print-time yes; };


Note: if you don't want to log DNS queries, change querylog yes; line in the global options in the /etc/named.conf file above to be no instead of yes, then comment out both the category queries { log_queries; }; and the channel log_queries... lines in the logging section.

Next, create the /var/named folder, where we'll put our zone configuration files

$ mkdir /var/named

Download the current hinting cache and save it for BIND's use

$ wget -O /var/named/

Next, download the template and a list of ad servers to block, and save these zone files. This is just one site and example method of blocking zones. I am not making a value judgement about the content of the advertisers listed in the file which is retrieved, and that content is regularly updated so I don't know what's in there in advance when you get around to downloading it. Consider that a disclaimer.

(optional) You may want to edit the /var/named/named.advert text file after you've downloaded it, in case there are any ad servers you don't want to block. If you don't want to block any ad servers, still download the and just touch /var/named/named.advert instead of downloading the file.

$ wget -O /var/named/
$ wget -O /var/named/named.advert\&mimetype=plaintext\&showintro=0

For details about those two ad blocking files above, see and its formats, and check the most recent update date on the block list from the serverlist to see whether you need to download a new copy.

Even if you don't use his list of ad servers to block, the template is still handy, so you can use it from your own manual block list. The current version of that is at, however here is the contents of that file for your reference in case goes offline:

; BIND db file for ad servers - point all addresses to localhost
; This file comes from:
; A site with a list of ad servers and details on how to use it to
; block ads on the Internet. Plus some BIND stuff and other bits.
;  -

$TTL	86400	; one day

@       IN      SOA (
                        2002061000       ; serial number YYMMDDNN
                        28800   ; refresh  8 hours
                        7200    ; retry    2 hours
                        864000  ; expire  10 days
                        86400 ) ; min ttl  1 day


*		IN      A

Next, create a basic file

$ cat > /var/named/ <<'END'
$TTL    86400 ; 24 hours could have been written as 24h or 1D
$ORIGIN localhost.
; line below expands to: localhost 1D IN SOA localhost root.localhost
@  1D  IN        SOA @  root (
                              2002022401 ; serial
                              3H ; refresh
                              15 ; retry
                              1w ; expire
                              3h ; minimum
@  1D  IN  NS @
   1D  IN  A


Next, create a basic named.local reverse lookup file. Replace the three instances of myname with the name of your computer

$ cat > /var/named/named.local <<'END'
$TTL    86400 ; 24 hours could have been written as 24h or 1D IN SOA myname.local. root.myname.local. (
                           19970331    ; serial number
                           10800       ; refresh every 3 hours
                           10800       ; retry every 3 hours
                           604800      ; expire after a week
                           86400 )     ; TTL of 1 day   IN  NS  myname.local.
1                       IN  PTR localhost.local.

Next, we'll create another list for blocking zones/domains, which you'll update manually. If you don't have anything you'd like to block, you can touch /var/named/named.blocked

If you've got some hosts file entries you'd like to convert to BIND format for this purpose, there is a converter available.

$ cat > /var/named/named.blocked <<'END'
zone "" { type master; notify no; file ""; };

Create a folder to hold the BIND log files:

$ mkdir /var/log/named

Next, we need to create a LaunchDaemon for BIND

$ cat > /Library/LaunchDaemons/org.isc.named.plist <<'END'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "">
<plist version="1.0">

Ensure it has the right ownership and permissions:

$ chown root:wheel /Library/LaunchDaemons/org.isc.named.plist
$ chmod 644 /Library/LaunchDaemons/org.isc.named.plist

Next, launch BIND. It should also start automatically on system reboot.

$ launchctl load -wF /Library/LaunchDaemons/org.isc.named.plist

Finally, don't forget to exit out of your root shell:

$ exit

Do a quick check

BIND should have started automatically. It will store its logs in /var/log/named/ and the particular log file you should check is named.log

$ tail /var/log/named/named.log

20-Sep-2015 18:10:58.910 general: all zones loaded
20-Sep-2015 18:10:58.911 general: running

Check the status of BIND using rndc:

$ /usr/local/sbin/rndc status

version: BIND 9.10.3 <id:2299900>
boot time: Sun, 20 Sep 2015 03:45:31 GMT
last configured: Sun, 20 Sep 2015 22:10:58 GMT
CPUs found: 8
worker threads: 8
UDP listeners per interface: 4
number of zones: 2520
debug level: 0
xfers running: 0
xfers deferred: 0
soa queries in progress: 0
query logging is ON
recursive clients: 0/0/1000
tcp clients: 0/100
server is up and running

Congrats, it's running. Now, let's try to resolve something with it:

$ dig @ a

; <<>> DiG 9.10.3 <<>> @ a
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 25910
;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 4, ADDITIONAL: 3

; EDNS: version: 0, flags:; udp: 4096
;                 IN      A

;; ANSWER SECTION:          300     IN      CNAME 60      IN      A 60      IN      A 60      IN      A 60      IN      A

;; AUTHORITY SECTION:        172800  IN      NS        172800  IN      NS        172800  IN      NS        172800  IN      NS

;; ADDITIONAL SECTION:          86400   IN      A          86400   IN      A

;; Query time: 735 msec
;; WHEN: Sun Sep 20 20:15:36 EDT 2015
;; MSG SIZE  rcvd: 251

If everything worked okay, you should see a result similar to the above. Yahoo may resolve to different results, but as long as you get results rather than an error, you should be good to go.

Now, do the exact same command again, and you'll see your Query time drop to almost nothing. BIND is caching your results (until the TTL runs out, as it was set by Yahoo in this case), so future name resolution is practically instant.

$ dig @ a

;; Query time: 0 msec
;; WHEN: Sun Sep 20 20:18:02 EDT 2015

Modify Network Preferences

The final step is to modify your network preferences, and change your nameserver to be instead of whatever they are.

You can find this by clicking on System Preferences then Network, selecting your Ethernet (assuming you connect to the Internet via Ethernet), then clicking on Advanced, then click on the DNS tab.

Suggestion: Write down the existing DNS entries in case you want to revert back to using them instead of this BIND installation.

Click on any entries in the DNS Server section and press the [-] (minus) button to remove them. Then click on the [+] (plus) button to add a new entry, and enter

Performing that step will also automatically change your /etc/resolv.conf file.

Other useful commands

Execute the following commands to stop the BIND service:

$ sudo launchctl stop /Library/LaunchDaemons/org.isc.named
$ sudo launchctl unload /Library/LaunchDaemons/org.isc.named.plist

Execute the following commands to start the BIND service:

$ sudo launchctl load -wF /Library/LaunchDaemons/org.isc.named.plist
$ sudo launchctl start /Library/LaunchDaemons/org.isc.named

Check if there are any errors in your /etc/named.conf:

$ /usr/local/sbin/named-checkconf /etc/named.conf

Check if there are any errors in a zone file:

$ /usr/local/sbin/named-checkzone localhost /var/named/

Reload the zone files through rndc:

$ /usr/local/sbin/rndc reload

Reload the named (BIND) zones through the process:

$ ps -ef | grep named | grep -v grep
    0 80983     1   0 11:45pm ??         0:04.78 /usr/local/sbin/named -f
$ kill -HUP 80983

Important Note

If you do a man rndc you'll see that rndc reload (and rndc reconfig) says that it reloads the configuration file (and the zones). In practice, however, I found that I had made a configuration file change that was not picked up by either of these rndc commands.

The only reliable way on OS X so far that i've found to pick up the config file changes in /etc/named.conf is to use launchctl to stop then unload, then load (it should start automatically, which you can verify using /usr/local/sbin/rndc status).

When I find a better way to reload the config I'll update this document.

Suggested further reading

$ /usr/local/sbin/rndc -h
$ man rndc
$ man named.conf

To provide feedback, corrections or suggestions, please send an email to: back feed @ height8 .com (remove the spaces from the email address if you're doing a copy/paste). In your email, please mention you are referring to: info/os/osx/named