Bind 9: Setting Up a DNS Record
Understanding Bind9 Config Files
named.conf
named.conf.options
named.conf.local
db.<domain>
Now that we know the basics lets add a DNS record.
Step 1: Check if your DNS server is accessible
To do this I use two commands. One tells me if I can reach the server and the second one tells me what is the routing to reach the server
ping 192.<>.<>.70
# You should see some output like below
PING 192.<>.<>.<> (192.<>.<>.<> ): 56 data bytes
64 bytes from 192.<>.<>.<> : icmp_seq=0 ttl=63 time=4.145 ms
64 bytes from 192.<>.<>.<> : icmp_seq=1 ttl=63 time=3.333 ms
64 bytes from 192.<>.<>.<> : icmp_seq=2 ttl=63 time=2.750 ms
traceroute 192.<>.<>.70
# You should see some output like below
traceroute to 192.<>.<>.<> (192.<>.<>.<> ), 64 hops max, 40 byte packets
1 192.<>.<>.1 (192.<>.<>.<> ) 8.457 ms 3.254 ms 2.937 ms
2 192.<>.<>.70 (192.<>.<>.<> ) 4.095 ms 4.459 ms 4.005 ms
Step 2: Update the named.conf.options file to include your DNS server defaults and ACLs’
In my name.conf.options, I will set up an ACL (Access Control List) for some additional security. ACL is a security feature which defines who is allowed to do what on your DNS server.
Think of it like a bouncer at a VIP club. Bouncer has a list of who can enter. If you are on the list, you get in. All others are turned away. ACLs does the same thing. In this case, I am making sure only devices in my network can DNS quarries to my Bind9 server.
sudo nano /etc/bind/named.conf.options
# Add a config similar to below
# Define trusted networks
# MUST be at the TOP before options block
# Include all of your Subnets/ VLANs here
acl "trusted" {
192.<>.<>.0/24;
192.<>.<>.0/24;
192.<>.<>.0/24;
[localhost](<http://localhost>);
localnets;
};
# These are your options/settings
options {
directory "/var/cache/bind";
recursion yes; # Allow to resolve external domains like google.com
allow-query { trusted; }; # Setting to trusted means only accessible by ips from the acls
allow-query-cache { trusted; }; # Setting to trusted means only accessible by ips from the acls
allow-recursion { trusted; }; # Setting to trusted means only accessible by ips from the acls
forwarders {
1.1.1.1;
8.8.8.8;
};
dnssec-validation no;
listen-on { any; };
listen-on-v6 { any; };
allow-transfer { none; }; # Prevent zone transfers
};
Verify there are no syntax errors
sudo named-checkconf /etc/bind/named.conf.options
Step 3: Create a local zone
# Lets create a dir to keep all zone files
sudo mkdir -p /etc/bind/zones
# Create zone file
sudo nano /etc/bind/named.conf.local
# Add the following to your named.conf.local
# Makesure to replace the <domain-name>
zone "<domain-name>" {
type master; # This server is authoritative
file "/etc/bind/zones/db.<domain-name>"; # Path to zone file
allow-query { trusted; }; # Only trusted networks
allow-update { none; }; # Prevent dynamic updates
allow-transfer { none; }; # No zone transfers
};
Recommended by LinkedIn
Step 4: Create your forwarding zone
This file contains the DNZ records
sudo nano /etc/bind/zones/db.<domain-name>
# Add the following config
$TTL 604800
@ IN SOA ns1.<domain-name>. admin.<domain-name>. (
2025110901 ; Serial (YYYYMMDDNN format)
604800 ; Refresh (1 week)
86400 ; Retry (1 day)
2419200 ; Expire (4 weeks)
604800 ) ; Negative Cache TTL (1 week)
;
; Name servers
@ IN NS ns1.<domain-name>.
; A records - hostname to IP mappings
ns1 IN A 192.<>.<>.70 ; DNS server itself
homeassistant IN A 192.<>.<>.177 ; Home Assistant
homeassist IN A 192.<>.<>.177 ; Shorter name
; CNAME records - aliases
ha IN CNAME homeassistant.<domain-name>.
Step 5: Validate if there are no configuration issues
# Check main configuration
sudo named-checkconf
# Check forward zone
sudo named-checkzone <domain-name> /etc/bind/zones/db.<domain-name>
You should see an output like this
zone <domain-name>/IN: loaded serial 2025110901
OK
Note: Every time you make a change to /etc/bind/zones/db.<domain-name> remember to update the serial
Step 6: If no errors restart Bind9 service
sudo systemctl restart named
sudo systemctl status named
# You should see this as an output if everything is good
named.service - BIND Domain Name Server
Loaded: loaded
Active: active (running)
Step 7: Test domain names are resolved within Bind9
dig @192.<>.<>.70 homeassistant.home.local
dig @192.<>.<>.70 homeassist.home.local
dig @192.<>.<>.70 ha.home.local
# You should see an output like this
; <<>> DiG 9.20.15-1+ubuntu24.04.1+deb.sury.org+1-Ubuntu <<>> @192.<>.<>.70 ha.<domain-name>
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 42115
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: ab91426908e2e1ea01000000691016b4e3ce1b1ba65445b1 (good)
;; QUESTION SECTION:
;ha.labconsulting.net. IN A
;; ANSWER SECTION:
ha.<domain-name>. 604800 IN CNAME homeassistant.<domain-name>.
homeassistant.<domain-name>. 604800 IN A 192.<>.<>.177
;; Query time: 0 msec
;; SERVER: 192.<>.<>.70#53(192.<>.<>.70) (UDP)
;; WHEN: Sun Nov 09 04:21:08 UTC 2025
;; MSG SIZE rcvd: 121
Step 8: Update your routers domain resolver settings
Typically this is set to auto. If that is the case then change it to manual and add your Bind9 server ip address and at least one other knows DNS resolver like 1.1.1.1 (CloudFlare)
Note: For anyone who is using UnitFi CloudGateways, you will also need to add a policy to forward your local domain queries to be forwarded to the Bind9 server. Without this policy, UniFi CloudGateway does not seem to pass the query to Bind9. I spent few hours troubleshooting this
Step 9: Test from your device.
# Run this command in your terminal
dig @192.<>.<>.70 homeassistant.<domain-name>
# You should see a result similar to below
; <<>> DiG 9.10.6 <<>> @192.<>.<>.70 homeassistant.<domain-name>
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 23301
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;homeassistant.<domain-name>. IN A
;; ANSWER SECTION:
homeassistant.l<domain-name>. 746 IN A 192.<>.<>.177
;; Query time: 4 msec
;; SERVER: 192.168.4.70#53(192.168.4.70)
;; WHEN: Sun Nov 09 15:30:07 AEDT 2025
;; MSG SIZE rcvd: 107
Test from your browser
Note: At the time of writing I have trouble getting Safari to resolve this domain. However, it works with Chrome.
What is Next
As you can see, this connection is not secure. In my next blog I will address how we can add TLS verification and if time permits how to set up a reverse proxy service like nginx proxy manager.