How to Configure Split-horizon DNS with Bind9 Views on Ubuntu Server
Learning how to configure split-horizon DNS with Bind9 Views on Ubuntu Server is one of the most practical skills you can add to your server administration toolkit. Split-horizon DNS lets you serve different DNS responses depending on where a query originates. Internal users get private IP addresses. External users get public-facing ones. This is especially useful for companies running internal services behind a firewall. It keeps your network clean, secure, and easy to manage. In this tutorial, you’ll set up two Bind9 views , one for internal clients and one for external clients , on Ubuntu Server. By the end, you’ll have a fully working split-horizon DNS configuration you can adapt for your own environment.
Prerequisites for Configuring Split-Horizon DNS with Bind9 Views
Before you begin, make sure you have the following in place:
Required software and access:
- Ubuntu Server 20.04 or 22.04 (fresh install recommended)
- Root or sudo access to the server
- Bind9 installed (covered in Step 1)
- A registered domain name (e.g., example.com)
- Basic familiarity with DNS concepts like zones, records, and resolvers
Assumed knowledge: You should be comfortable working in the Linux terminal. You don’t need to be a DNS expert, but knowing what an A record and a zone file are will help.
Estimated time: 30–45 minutes depending on your familiarity with Bind9.
You’ll also want two IP ranges defined before you start. For this tutorial, the internal network is 192.168.1.0/24 and the external network represents everything else. Adjust these to match your actual setup.
For deeper background on how Bind9 works, check the official Bind9 documentation.
Step-by-Step Guide to Split-Horizon DNS with Bind9 Views on Ubuntu
See also: How to Create Custom Wordpress Gutenberg Blocks with the Block Editor Api
Step 1: Install Bind9 on Ubuntu Server
First, update your package list and install Bind9.
sudo apt update
sudo apt install bind9 bind9utils bind9-doc -y
Once installed, verify the service is running:
sudo systemctl status bind9
You should see active (running) in the output. If not, start it with sudo systemctl start bind9.
Step 2: Back Up the Default Configuration
Always back up your config files before editing them. This saves you if something goes wrong.
sudo cp /etc/bind/named.conf.local /etc/bind/named.conf.local.bak
sudo cp /etc/bind/named.conf.options /etc/bind/named.conf.options.bak
Step 3: Define ACLs in named.conf.options
Open the options file:
sudo nano /etc/bind/named.conf.options
Add ACL blocks at the very top, before the options block:
acl "internal-clients" {
192.168.1.0/24;
localhost;
localnets;
};
acl "external-clients" {
any;
};
Inside the options block, add these lines to allow recursion for internal clients only:
options {
directory "/var/cache/bind";
recursion yes;
allow-recursion { internal-clients; };
forwarders {
8.8.8.8;
8.8.4.4;
};
dnssec-validation auto;
listen-on { any; };
};
Save and close the file with Ctrl+X, then Y, then Enter.
Step 4: Configure Views in named.conf.local
This is the core step. Open the local config file:
sudo nano /etc/bind/named.conf.local
Add the following two views. The internal view serves private IPs. The external view serves public IPs.
view "internal" {
match-clients { internal-clients; };
recursion yes;
zone "example.com" {
type master;
file "/etc/bind/zones/db.example.com.internal";
};
};
view "external" {
match-clients { external-clients; };
recursion no;
zone "example.com" {
type master;
file "/etc/bind/zones/db.example.com.external";
};
};
Save and close the file.
Step 5: Create the Zone Directory
sudo mkdir -p /etc/bind/zones
Step 6: Create the Internal Zone File
sudo nano /etc/bind/zones/db.example.com.internal
Add the following content. Replace 192.168.1.10 with your internal server IP.
$TTL 604800
@ IN SOA ns1.example.com. admin.example.com. (
2024010101 ; Serial
3600 ; Refresh
1800 ; Retry
604800 ; Expire
86400 ) ; Negative Cache TTL
@ IN NS ns1.example.com.
ns1 IN A 192.168.1.10
@ IN A 192.168.1.10
www IN A 192.168.1.10
mail IN A 192.168.1.20
Save and close.
Step 7: Create the External Zone File
sudo nano /etc/bind/zones/db.example.com.external
Add the following. Replace 203.0.113.10 with your real public IP.
$TTL 604800
@ IN SOA ns1.example.com. admin.example.com. (
2024010101 ; Serial
3600 ; Refresh
1800 ; Retry
604800 ; Expire
86400 ) ; Negative Cache TTL
@ IN NS ns1.example.com.
ns1 IN A 203.0.113.10
@ IN A 203.0.113.10
www IN A 203.0.113.10
mail IN A 203.0.113.20
Save and close.
Step 8: Validate and Restart Bind9
Check your configuration for syntax errors:
sudo named-checkconf
Check each zone file:
sudo named-checkzone example.com /etc/bind/zones/db.example.com.internal
sudo named-checkzone example.com /etc/bind/zones/db.example.com.external
If no errors appear, restart Bind9:
sudo systemctl restart bind9
Test from an internal client:
dig @192.168.1.10 www.example.com
You should get 192.168.1.10 back. Test from an external source and you should get 203.0.113.10.
Troubleshooting Common Bind9 View Configuration Issues
Error: “no matching view” in logs
Check /var/log/syslog for Bind9 errors. This usually means your ACLs don’t cover all possible clients. Add any; as a catch-all in your last view.
Both clients get the same response
Double-check your ACL definitions. Make sure the internal ACL lists your actual subnet. Run sudo named-checkconf again to catch any typos.
Bind9 won’t start after changes
Run this command to see detailed errors:
sudo journalctl -xe | grep named
Zone serial numbers must be unique. If you copy a zone file, update the serial number. The format YYYYMMDDNN works well.
Recursion refused for internal clients
Make sure your allow-recursion directive references the correct ACL name. ACL names are case-sensitive in Bind9.
For more detail on DNS record types and zone file syntax, the Ubuntu Server DNS documentation is a great reference.
Conclusion
You now know how to configure split-horizon DNS with Bind9 Views on Ubuntu Server. You’ve set up ACLs, created two separate views, written internal and external zone files, and tested the whole setup. This configuration gives you precise control over what DNS data different clients receive. Internal users stay on your private network. External users see only your public-facing addresses. From here, you can add more zones, set up reverse DNS, or add DNSSEC signing to your zones for extra security. Split-horizon DNS is a foundational technique. Getting it right makes your entire infrastructure easier to manage and more secure.
