Private DNS Server Using Bind¶
Prerequisites and Assumptions¶
- A server running Rocky Linux
- Several internal servers that need to be accessed only locally, but not over the Internet
- Several workstations that need access to these same servers that exist on the same network
- A healthy comfort level with entering commands from command line
- Familiarity with a command line editor (we are using vi in this example)
- Able to use either firewalld or iptables for creating firewall rules. We've provided both iptables and firewalld options. If you plan to use iptables, use the Enabling Iptables Firewall procedure
Introduction¶
External, or public, DNS servers are used on the Internet to map host names to IP addresses and, in the case of PTR (known as "pointer" or "reverse") records, to map the IP to the host name. This is an essential part of the Internet. It makes your mail server, web server, FTP server, or many other servers and services work as expected no matter where you are.
On a private network, particularly one that is being used for developing multiple systems, you can use your Rocky Linux workstation's /etc/hosts file to map a name to an IP address.
This will work for your workstation, but not for any other machine on your network. If you want to make things universally applied, then the best method is to take some time out and create a local, private DNS server to handle this for all of your machines.
If you were creating production-level public DNS servers and resolvers, then this author would probably recommend the more robust PowerDNS authoritative and recursive DNS, which is easily installed on Rocky Linux servers. However, that is simply overkill for a local network that won't be exposing its DNS servers to the outside world. That is why we have chosen bind for this example.
The DNS Server Components Explained¶
As stated, DNS separates services into authoritative and recursive servers. These services are now recommended to be separate from each other on separate hardware or containers.
The authoritative server is the storage area for all IP addresses and host names, and the recursive server is used to lookup addresses and host names. In the case of our private DNS server, both the authoritative and the recursive server services will run together.
Installing and Enabling Bind¶
The first step is to install packages. In the case of bind we need to execute the following command:
dnf install bind bind-utils
The service daemon for bind is called named, and we need to enable this to start on boot:
systemctl enable named
And then we need to start it:
systemctl start named
Configuration¶
Before making changes to any configuration file, it is a good idea to make a backup copy of the original installed working file, in this case named.conf:
cp /etc/named.conf /etc/named.conf.orig
That will help in the future if errors are introduced into the configuration file. It is always a good idea to make a backup copy before making changes.
These changes require us to edit the named.conf file, to do this, we are using vi, but you can substitute your favorite command line editor (the editor nano
is also installed in Rocky Linux and is easier to use than vi
):
vi /etc/named.conf
First thing we want to do is turn off listening on the localhost, this is done by remarking out with a "#" sign, these two lines in the "options" section. What this does is to effectively shut down any connection to the outside world.
This is helpful, particularly when we go to add this DNS to our workstations, because we want the DNS server to only respond when the IP address requesting the service is local, and simply not respond at all if the service that is being looked up is on the Internet.
This way, the other configured DNS servers will take over nearly immediately to look up the Internet based services:
options {
# listen-on port 53 { 127.0.0.1; };
# listen-on-v6 port 53 { ::1; };
Finally, skip down to the bottom of the named.conf file and add a section for your network. Our example is using ourdomain, so sub in what you want to call your LAN hosts:
# primary forwward and reverse zones
//forward zone
zone "ourdomain.lan" IN {
type master;
file "ourdomain.lan.db";
allow-update { none; };
allow-query {any; };
};
//reverse zone
zone "1.168.192.in-addr.arpa" IN {
type master;
file "ourdomain.lan.rev";
allow-update { none; };
allow-query { any; };
};
Now save your changes (for vi, SHIFT:wq!
)
The Forward and Reverse Records¶
Next, we need to create two files in /var/named
. These files are the ones that you will edit if you add machines to your network that you want to include in the DNS.
The first is the forward file to map our IP address to the hostname. Again, we are using "ourdomain" as our example here. Note that the IP of our local DNS here is 192.168.1.136. The hosts are added at the bottom of this file.
vi /var/named/ourdomain.lan.db
The file will look something like this when you are done:
$TTL 86400
@ IN SOA dns-primary.ourdomain.lan. admin.ourdomain.lan. (
2019061800 ;Serial
3600 ;Refresh
1800 ;Retry
604800 ;Expire
86400 ;Minimum TTL
)
;Name Server Information
@ IN NS dns-primary.ourdomain.lan.
;IP for Name Server
dns-primary IN A 192.168.1.136
;A Record for IP address to Hostname
wiki IN A 192.168.1.13
www IN A 192.168.1.14
devel IN A 192.168.1.15
Add as many hosts as you need to the bottom of the file along with their IP addresses and then save your changes.
Next, we need a reverse file to map our hostname to the IP address, In this case, the only part of the IP that you need is the last octet (in an IPv4 address each number separated by a period, is an octet) of the host and then the PTR and hostname.
vi /var/named/ourdomain.lan.rev
And the file should look something like this when you are done.:
$TTL 86400
@ IN SOA dns-primary.ourdomain.lan. admin.ourdomain.lan. (
2019061800 ;Serial
3600 ;Refresh
1800 ;Retry
604800 ;Expire
86400 ;Minimum TTL
)
;Name Server Information
@ IN NS dns-primary.ourdomain.lan.
;Reverse lookup for Name Server
136 IN PTR dns-primary.ourdomain.lan.
;PTR Record IP address to HostName
13 IN PTR wiki.ourdomain.lan.
14 IN PTR www.ourdomain.lan.
15 IN PTR devel.ourdomain.lan.
Add all of the hostnames that appear in the forward file and then save your changes.
What All Of This Means¶
Now that we have all of this added in and are preparing to restart our bind DNS server, let's just explore some of the terminology that is used in these two files.
Just making things work isn't good enough if you don't know what each term means, right?
- TTL appears in both files and it stands for "Time To Live". TTL tells the DNS server how long to keep its cache in place before requesting a fresh copy. In this case, the TTL is the default setting for all records unless a specific record TTL is set. The default here is 86400 seconds or 24 hours.
- IN stands for Internet. In this case, we aren't actually using the Internet, so think of this as the Intranet.
- SOA stands for "Start Of Authority" or what the primary DNS server is for the domain.
- NS stands for "name server"
- Serial is the value used by the DNS server to verify that the contents of the zone file are up-to-date.
- Refresh specifies how often a slave DNS server should do a zone transfer from the master.
- Retry specifies the length of time in seconds to wait before trying again on a failed zone transfer.
- Expire specifies how long a slave server should wait to answer a query when the master is unreachable.
- A Is the host address or forward record and is only in the forward file (above).
- PTR Is the pointer record better known as the "reverse" and is only in our reverse file (above).
Testing Configurations¶
Once we have gotten all of our files created, we need to make sure that the configuration files and zones are in good working order before we start the bind service again.
Check the main configuration:
named-checkconf
This should return an empty result if everything is OK.
Then check the forward zone:
named-checkzone ourdomain.lan /var/named/ourdomain.lan.db
This should return something like this if all is well:
zone ourdomain.lan/IN: loaded serial 2019061800
OK
And finally check the reverse zone:
named-checkzone 192.168.1.136 /var/named/ourdomain.lan.rev
Which should return something like this if all is well:
zone 192.168.1.136/IN: loaded serial 2019061800
OK
Assuming that everything looks good, go ahead and restart bind:
systemctl restart named
9.0 Using IPv4 On Your LAN¶
In order to use ONLY IPv4 on your LAN, you need to make one change in /etc/sysconfig/named
:
vi /etc/sysconfig/named
OPTIONS="-4"
Now save those changes (again, for vi, SHIFT:wq!
)
9.0 Testing Machines¶
You need to add the DNS server (in our example 192.168.1.136) to each machine that you want to have access to the servers that you added to your local DNS. We are only going to show you an example of how to do this on a Rocky Linux workstation, but there are similar methods for other Linux distributions, as well as Windows and Mac machines.
Keep in mind that you will want to just add the DNS servers to the list, not replace what is currently there, as you will still need Internet access, which will require your currently assigned DNS servers. These might be assigned via DHCP (Dynamic Host Configuration Protocol) or statically assigned.
We will add our local DNS with nmcli
and then restart the connection.
Stupid Profile Names
In NetworkManager, the connections are not modified by the name of the device but by the name of the profile. This can be things like "Wired connection 1" or "Wireless connection 1". You can see the profile by running nmcli
without any parameters:
nmcli
This will show you output such as this:
enp0s3: connected to Wired Connection 1
"Intel 82540EM"
ethernet (e1000), 08:00:27:E4:2D:3D, hw, mtu 1500
ip4 default
inet4 192.168.1.140/24
route4 192.168.1.0/24 metric 100
route4 default via 192.168.1.1 metric 100
inet6 fe80::f511:a91b:90b:d9b9/64
route6 fe80::/64 metric 1024
lo: unmanaged
"lo"
loopback (unknown), 00:00:00:00:00:00, sw, mtu 65536
DNS configuration:
servers: 192.168.1.1
domains: localdomain
interface: enp0s3
Use "nmcli device show" to get complete information about known devices and
"nmcli connection show" to get an overview on active connection profiles.
Before we even start modifying the connection, you should name this something sane, like the name of the interface (note the "\" below escapes the spaces in the name):
nmcli connection modify Wired\ connection\ 1 con-name enp0s3
Once you've done this, run nmcli
by itself again and you will see something like this:
enp0s3: connected to enp0s3
"Intel 82540EM"
ethernet (e1000), 08:00:27:E4:2D:3D, hw, mtu 1500
ip4 default
inet4 192.168.1.140/24
route4 192.168.1.0/24 metric 100
route4 default via 192.168.1.1 metric 100
...
This will make the remaining configuration for the DNS much easier!
Assuming that your connection profile name is "enp0s3", we will include the already configured DNS but add our local DNS server first:
nmcli con mod enp0s3 ipv4.dns '192.168.1.138,192.168.1.1'
You can have more DNS servers, and for a machine configured with public DNS servers, say Google's open DNS, you can have something like this instead:
nmcli con mod enp0s3 ipv4.dns '192.168.1.138,8.8.8.8,8.8.4.4'
Once you've added the DNS servers that you want to the connection, you should be able to resolve hosts in ourdomain.lan, as well as Internet hosts.
9.0 Firewall Rules - firewalld
¶
firewalld
By Default
With Rocky Linux 9.0 and above, using iptables
rules is deprecated. You should use firewalld
instead.
We aren't making any assumptions about the network or services that might be needed, except that we are turning on SSH access and DNS access for our LAN network only. For this, we will use the firewalld
built-in zone, "trusted". We will also have to make some service changes to the "public" zone in order to limit SSH access to the LAN.
The first step is to add our LAN network to the "trusted" zone:
firewall-cmd --zone=trusted --add-source=192.168.1.0/24 --permanent
Next, we need to add our two services to the "trusted" zone:
firewall-cmd --zone=trusted --add-service=ssh --permanent
firewall-cmd --zone=trusted --add-service=dns --permanent
Finally, we need to remove the SSH service from our "public" zone, which is on by default:
firewall-cmd --zone=public --remove-service=ssh --permanent
Next, reload the firewall and then list out the zones that we've made changes to:
firewall-cmd --reload
firewall-cmd --zone=trusted --list-all
Which should show that you have correctly added the services and the source network:
trusted (active)
target: ACCEPT
icmp-block-inversion: no
interfaces:
sources: 192.168.1.0/24
services: dns ssh
ports:
protocols:
forward: no
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
Listing out the "public" zone should show that SSH access is no-longer allowed:
firewall-cmd --zone=public --list-all
Which should show you:
public
target: default
icmp-block-inversion: no
interfaces:
sources:
services: cockpit dhcpv6-client
ports:
protocols:
forward: no
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
These rules should get you DNS resolution on your private DNS server from hosts on the 192.168.1.0/24 network. In addition, you should be able to SSH from any of those hosts into your private DNS server.
8.6 Using IPv4 On Your LAN¶
If you are using IPv4 only on your LAN, then you need to make two changes. The first is in /etc/named.conf
and the second is in /etc/sysconfig/named
First, get back into the named.conf
file again with vi /etc/named.conf
. We need to add the following option anywhere in the options section.
filter-aaaa-on-v4 yes;
This is shown in the image below:
Once you've made the change, save it and exit the named.conf
(for vi, SHIFT:wq!
)
Next we need to make a similar change to /etc/sysconfig/named
:
vi /etc/sysconfig/named
And then add this to the bottom of the file:
OPTIONS="-4"
Now save those changes (again, for vi, SHIFT:wq!
)
8.6 Testing Machines¶
You need to add the DNS server (in our example 192.168.1.136) to each machine that you want to have access to the servers that you added to your new local DNS. We are only going to show you an example of how to do this on a Rocky Linux workstation, but there are similar methods for other Linux distributions, as well as Windows and Mac machines.
Keep in mind that you will want to just add the DNS server in the list, as you will still need Internet access, which will require your currently assigned DNS servers. These might be assigned via DHCP (Dynamic Host Configuration Protocol) or statically assigned.
On a Rocky Linux workstation where the enabled network interface is eth0, you would use:
vi /etc/sysconfig/network-scripts/ifcfg-eth0
If your enabled network interface is different, you will need to substitute that interface name. The configuration file that you open will look something like this for a statically assigned IP (not DHCP as mentioned above). In the example below, our machine's IP address is 192.168.1.151:
DEVICE=eth0
BOOTPROTO=none
IPADDR=192.168.1.151
PREFIX=24
GATEWAY=192.168.1.1
DNS1=8.8.8.8
DNS2=8.8.4.4
ONBOOT=yes
HOSTNAME=tender-kiwi
TYPE=Ethernet
MTU=
We want to substitute in our new DNS server for the primary (DNS1) and then move each of the other DNS servers down one so that it is like this:
DEVICE=eth0
BOOTPROTO=none
IPADDR=192.168.1.151
PREFIX=24
GATEWAY=192.168.1.1
DNS1=192.168.1.136
DNS2=8.8.8.8
DNS3=8.8.4.4
ONBOOT=yes
HOSTNAME=tender-kiwi
TYPE=Ethernet
MTU=
Once you've made the change, either restart the machine or restart networking with:
systemctl restart network
Now you should be able to get to anything in the ourdomain.lan domain from your workstations, plus still be able to resovle and get to Internet addresses.
8.6 Firewall Rules¶
Adding The Firewall Rules - iptables
¶
Regarding iptables
While iptables
rules still work in Rocky Linux 8.6, we recommend moving to the firewalld
rules in the section below. The reason is that in future versions of Rocky Linux, iptables
will be deprecated and removed. In addition, firewalld
is the default way of doing things. You will find more examples of using firewalld
when looking for help, than for using iptables
. We've included the iptables
rules here, but for the best results and for future-proofing, we recommend moving to firewalld
now.
First, create a file in /etc called "firewall.conf" that will contain the following rules. This is a bare minimum rule set, and you may need to tweak this for your environment:
#!/bin/sh
#
#IPTABLES=/usr/sbin/iptables
# Unless specified, the defaults for OUTPUT is ACCEPT
# The default for FORWARD and INPUT is DROP
#
echo " clearing any existing rules and setting default policy.."
iptables -F INPUT
iptables -P INPUT DROP
iptables -A INPUT -p tcp -m tcp -s 192.168.1.0/24 --dport 22 -j ACCEPT
# dns rules
iptables -A INPUT -p udp -m udp -s 192.168.1.0/24 --dport 53 -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp -j REJECT --reject-with tcp-reset
iptables -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
/usr/sbin/service iptables save
Let's evaluate the rules above:
- The first "iptables" line flushes the rules that are currently loaded (-F).
- Next, we are setting a default policy for the INPUT chain of DROP. This means, if the traffic is not explicitly allowed here, it is dropped.
- Next, we have an SSH rule for our local network, so that we can get into the DNS server remotely.
- Then we have our DNS allow rule, only for our local network. Note that DNS uses the UDP protocol (User Datagram Protocol).
- Next we allow INPUT from the local interface.
- Then if you have established a connection for something else, we are allowing related packets in as well.
- And finally we reject everything else.
- The last line tells iptables to save the rules so that when the machine restarts, the rules will load as well.
Once our firewall.conf file is created, we need to make it executable:
chmod +x /etc/firewall.conf
Then run it:
/etc/firewall.conf
And this is what you should get in return. If you get something else, take a look at your script for errors:
clearing any existing rules and setting default policy..
iptables: Saving firewall rules to /etc/sysconfig/iptables:[ OK ]
Adding The Firewall Rules - firewalld
¶
With firewalld
, we are duplicating the rules highlighted in iptables
above. We aren't making any other assumptions about the network or services that might be needed. We are turning on SSH access and DNS access for our LAN network only. For this, we will use the firewalld
built-in zone, "trusted". We will also have to make some service changes to the "public" zone in order to limit SSH access to the LAN.
The first step is to add our LAN network to the "trusted" zone:
firewall-cmd --zone=trusted --add-source=192.168.1.0/24 --permanent
Next, we need to add our two services to the "trusted" zone:
firewall-cmd --zone=trusted --add-service=ssh --permanent
firewall-cmd --zone=trusted --add-service=dns --permanent
Finally, we need to remove the SSH service from our "public" zone, which is on by default:
firewall-cmd --zone=public --remove-service=ssh --permanent
Next, reload the firewall and then list out the zones that we've made changes to:
firewall-cmd --reload
firewall-cmd --zone=trusted --list-all
Which should show that you have correctly added the services and the source network:
trusted (active)
target: ACCEPT
icmp-block-inversion: no
interfaces:
sources: 192.168.1.0/24
services: dns ssh
ports:
protocols:
forward: no
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
Listing out the "public" zone should show that SSH access is no-longer allowed:
firewall-cmd --zone=public --list-all
public
target: default
icmp-block-inversion: no
interfaces:
sources:
services: cockpit dhcpv6-client
ports:
protocols:
forward: no
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
These rules should get you DNS resolution on your private DNS server from hosts on the 192.168.1.0/24 network. In addition, you should be able to SSH from any of those hosts into your private DNS server.
Conclusions¶
While using /etc/hosts on an individual workstation will get you access to a machine on your internal network, you can only use it on that one machine. By adding a private DNS server using bind, you can add hosts to the DNS and as long as the workstations have access to that private DNS server, they will be able to get to these local servers.
If you don't need machines to resolve on the Internet, but do need local access from several machines to local servers, then consider using a private DNS server instead.
Author: Steven Spencer
Contributors: Ezequiel Bruni