I just set up a simple but relatively highly available local DNS service (as shown in the cover image). Technically, it should be called a DNS recursive resolver, the first stop for local clients to perform DNS queries.

My company’s domain controller has DNS services. Still, recently there seems to be a problem with the resolution of some external domain names, and the domain controller is in the hands of the group, so I simply build one myself.

Table of Contents

Server Environment Preparation

  • 4 VMs with minimal configuration requirements
  • Fresh install of Debian 11.5.0
  • Basic information is planned as follows
ServerHostnameVirtual IPIP Address
Load Balancer (Master)debian-lb0110.0.0.1110.0.0.12
Load Balancer (Backup)debian-lb0210.0.0.1110.0.0.13
DNS (1)debian-dns01n/a10.0.0.14
DNS (2)debian-dns02n/a10.0.0.15

Basic Configuration

Set hostname

$ hostname debian-lb01
$ hostname debian-lb02
$ hostname debian-dns01
$ hostname debian-dns02
# or
# hostnamectl set-hostname xxxx

Configure network interface addresses

$ vi /etc/network/interfaces

=== debian-lb01 ===

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
auto ens192
allow-hotplug ens192
iface ens192 inet static
address 10.0.0.12/25
gateway 10.0.0.1

=== debian-lb02 ===

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
auto ens192
allow-hotplug ens192
iface ens192 inet static
address 10.0.0.13/25
gateway 10.0.0.1

=== debian-dns01 ===

# The loopback network interface
auto lo
iface lo inet loopback

iface lo inet static
address 10.0.0.11/32
scope host
description FOR LVS->DNS

# The primary network interface
auto ens192
allow-hotplug ens192
iface ens192 inet static
address 10.0.0.14/25
gateway 10.0.0.1

=== debian-dns02 ===

# The loopback network interface
auto lo
iface lo inet loopback

iface lo inet static
address 10.0.0.11/32
scope host
description FOR LVS->DNS

# The primary network interface
auto ens192
allow-hotplug ens192
iface ens192 inet static
address 10.0.0.15/25
gateway 10.0.0.1

Restart the network service to make the configuration take effect.

$ systemctl restart networking

Change time zone

$ timedatectl list-timezones | grep -i shanghai
$ timedatectl set-timezone Asia/Shanghai
# or
# ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# ls -l /etc/localtime
# cat /etc/timezone

Set date & time

$ date MMDDhhmmYYYY
# or
# date -s 2020-01-23
# date -s 12:34:56
# or
# timedatectl set-time "2020-01-23 12:34:56"
# timedatectl set-local-rtc 0

Time synchronization

=== debian-dns01 ===

$ apt install ntp -y
$ cp /etc/ntp.conf /etc/ntp.conf.bak

$ echo "driftfile /var/lib/ntp/ntp.drift
logfile /var/log/ntp.log
statsdir /var/log/ntpstats/
statistics loopstats peerstats clockstats
filegen loopstats file loopstats type day enable
filegen peerstats file peerstats type day enable
filegen clockstats file clockstats type day enable
server 10.0.0.24 iburst
server 10.0.0.25 iburst
server ntp.aliyun.com iburst
server ntp.tencent.com iburst
tos orphan 15
peer 10.0.0.15
restrict -4 default kod notrap nomodify nopeer noquery limited
restrict -6 default kod notrap nomodify nopeer noquery limited
restrict 127.0.0.1
restrict ::1" > /etc/ntp.conf

$ systemctl restart ntp
$ systemctl status ntp
$ ntpq -np

=== debian-dns02 ===

$ apt install ntp -y
$ cp /etc/ntp.conf /etc/ntp.conf.bak

$ echo "driftfile /var/lib/ntp/ntp.drift
logfile /var/log/ntp.log
statsdir /var/log/ntpstats/
statistics loopstats peerstats clockstats
filegen loopstats file loopstats type day enable
filegen peerstats file peerstats type day enable
filegen clockstats file clockstats type day enable
server 10.0.0.24 iburst
server 10.0.0.25 iburst
server ntp.aliyun.com iburst
server ntp.tencent.com iburst
tos orphan 15
peer 10.0.0.14
restrict -4 default kod notrap nomodify nopeer noquery limited
restrict -6 default kod notrap nomodify nopeer noquery limited
restrict 127.0.0.1
restrict ::1" > /etc/ntp.conf

$ systemctl restart ntp
$ systemctl status ntp
$ ntpq -np

=== debian-lb01 ===

$ echo NTP=10.0.0.14 >> /etc/systemd/timesyncd.conf
# or
# vi /etc/systemd/timesyncd.conf
$ timedatectl set-ntp true
$ systemctl restart systemd-timesyncd

=== debian-lb02 ===

$ echo NTP=10.0.0.15 >> /etc/systemd/timesyncd.conf
$ timedatectl set-ntp true
$ systemctl restart systemd-timesyncd

Verify that the time is in sync.

$ systemctl status systemd-timesyncd
$ timedatectl
$ timedatectl show
$ timedatectl timesync-status
$ timedatectl show-timesync

Configure dnsmasq

=== debian-dns01 ===

$ apt install dnsmasq -y

# /etc/resolv.conf
$ echo "nameserver 127.0.0.1" > /etc/resolv.conf

# /etc/dnsmasq.conf
$ cp /etc/dnsmasq.conf /etc/dnsmasq.conf.bak
$ echo "domain-needed
bogus-priv
strict-order
server=/mycompany.net/10.0.0.25
server=/mycompany.net/10.0.0.24
server=223.5.5.5
server=119.29.29.29
local=/dl/
interface=ens192
expand-hosts
domain=dl
cache-size=1500
log-queries
log-facility=/var/log/dnsmasq.log" > /etc/dnsmasq.conf

# /etc/hosts
$ vi /etc/hosts
# Add entries for local host addresses as needed.

$ systemctl restart dnsmasq.service
$ systemctl status dnsmasq.service
$ tail -n 20 /var/log/dnsmasq.log

=== debian-dns02 ===

$ apt install dnsmasq -y

$ scp root@dns01.dl:/etc/hosts /etc/hosts
# Pay attention to modify dns01 -> dns02 corresponding to 127.0.0.1 in hosts.
$ scp root@dns01.dl:/etc/resolv.conf /etc/resolv.conf
$ cp /etc/dnsmasq.conf /etc/dnsmasq.conf.bak
$ scp root@dns01.dl:/etc/dnsmasq.conf /etc/dnsmasq.conf
$ systemctl restart dnsmasq.service
$ systemctl status dnsmasq.service
$ tail -n 20 /var/log/dnsmasq.log

=== debian-lb01 & debian-lb02 ===

$ echo "nameserver 10.0.0.14
nameserver 10.0.0.15" > /etc/resolv.conf
# Configure the nameserver of the two LBs as DNS01 and DNS02.

Configure ipvsadm (direct routing)

=== debian-lb01 & debian-lb02 ===

$ echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
# or
# vi /etc/sysctl.conf
$ sysctl -p /etc/sysctl.conf
$ sysctl -a | grep ip_forward

$ apt install ipvsadm -y
$ ipvsadm -A -u 10.0.0.11:53 -s rr
$ ipvsadm -a -u 10.0.0.11:53 -r 10.0.0.14 -g
$ ipvsadm -a -u 10.0.0.11:53 -r 10.0.0.15 -g
$ ipvsadm -Sn > /etc/ipvsadm.rules
$ systemctl restart ipvsadm.service
$ systemctl status ipvsadm.service

$ ipvsadm -l
$ ipvsadm -ln
$ ipvsadm -lnc

=== debian-dns01 & debian-dns02 ===

$ echo "net.ipv4.conf.all.arp_ignore = 1" >> /etc/sysctl.conf
# or
# vi /etc/sysctl.conf
$ sysctl -p /etc/sysctl.conf
$ sysctl -a | grep arp_ignore

# If you configure sysctl in the following way, it will fail after reboot.
# sysctl net.ipv4.conf.all.arp_ignore=1
# or
# echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
# cat /proc/sys/net/ipv4/conf/all/arp_ignore

Configure keepalived

=== debian-lb01 ===

$ apt install keepalived -y

$ echo "vrrp_instance VI_1 {
    state MASTER
    interface ens192
    virtual_router_id 51
    priority 255
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass &U*I9o0p
    }
    virtual_ipaddress {
        10.0.0.11/25
    }
}" > /etc/keepalived/keepalived.conf

$ systemctl restart keepalived.service
$ systemctl status keepalived.service

=== debian-lb02 ===

$ apt install keepalived -y

$ echo "vrrp_instance VI_1 {
    state BACKUP
    interface ens192
    virtual_router_id 51
    priority 254
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass &U*I9o0p
    }
    virtual_ipaddress {
        10.0.0.11/25
    }
}" > /etc/keepalived/keepalived.conf

$ systemctl restart keepalived.service
$ systemctl status keepalived.service

Finished work~

Other commands that may be used

$ cat /etc/nsswitch.conf
$ ls /sys/class/net
$ ifdown ens192
$ ifup ens192
$ nc -uvz 10.0.0.14 123
$ nc -uvz 10.0.0.15 123
$ nc -uvz 10.0.0.14 53
$ nc -uvz 10.0.0.15 53