Linux VRRP

Categories: Linux

Here’s some configuration examples from a VRRP(Virtual Router Redundancy Protocol) experiment i did. This is used to create a high available DNS resolver with Unbound. I used RHEL 8 as my distribution of choice, but I’m sure this can be used on any RHEL deviate or linux distribution

Software requirements:

  • keepalived
  • unbound
  • net-tools

Topology: I have 2 VMs within the same network.

  • Host A (172.16.0.90)
  • Host B (172.16.0.91)
  • VIP(Virtual IP Address) 172.16.0.92
1. Support Floating IP in kernel

Create /etc/sysctl.d/01-vrrp.conf

net.ipv4.ip_nonlocal_bind=1

Append it by rebooting or running sysctl -p

2. Unbound.conf

Create /etc/unbound/unbound.conf

server:
username: "unbound"
directory: "/etc/unbound"
chroot: "/etc/unbound"
pidfile: "unbound.pid"
do-daemonize: no # Set to no when use-systemd is enabled
use-systemd: yes

#module-config: "validator iterator"

# General Settings
port: 53
do-ip4: yes
do-ip6: no
do-udp: yes
do-tcp: yes
interface: 0.0.0.0
interface: ::0
interface-automatic: yes
hide-identity: no
hide-version: no
version: ""
edns-buffer-size: 1232			# Prevent IP fragmentation. DNS Flag Day 2020
so-rcvbuf: 2m				#4m
so-sndbuf: 2m				#4m
so-reuseport: yes			# Faster UDP with multithreading (linux only)

# TCP
incoming-num-tcp: 10
outgoing-num-tcp: 10

# Perfomance Tuning
num-threads: 2				# number of cores. Threading is disabled if set to 1
num-queries-per-thread: 4096

# Caching
cache-min-ttl: 7200
cache-max-ttl: 86400
msg-buffer-size: 8192 # Default Value 65552
msg-cache-size: 50m
msg-cache-slabs: 4 # power of 2 to num-threads
rrset-cache-size: 100m # rrset=msg*2
rrset-cache-slabs: 4
infra-cache-slabs: 4
infra-cache-numhosts: 10000
infra-cache-min-rtt: 120
key-cache-size: 100k
key-cache-slabs: 1
neg-cache-size: 10k
prefetch: yes
prefetch-key: yes
#serve-expired: yes
#serve-expired-ttl: 86400

# Query localhost
do-not-query-localhost: no		# Default is yes. If no, then localhost can be used to send queries to.

# Private Addresses RFC1918
# DNS Rebinding Prevention
private-address: 10.0.0.0/8
private-address: 169.254.0.0/16
private-address: 172.16.0.0/12
private-address: 192.168.0.0/16
private-address: fd00::/8
private-address: fe80::/10

# Access List
access-control: 172.16.0.0/24 allow

# Forward DNS Requests to public resolvers
forward-zone:
name: "."
forward-tls-upstream: no
#forward-addr: 1.1.1.1		# Cloudflare DNS Primary
#forward-addr: 1.0.0.1		# Cloudflare DNS Secondary
#forward-addr: 1.1.1.2		# Cloudflare DNS Malware Filtering
#forward-addr: 1.0.0.2		# Cloudflare DNS Malware Filtering Secondary
forward-addr: 1.1.1.3		# Cloudflare DNS Malware + Adult Filtering
forward-addr: 1.0.0.3		# Cloudflare DNS Malware + Adult Filtering Secondary
#forward-addr: 8.8.8.8		# Google DNS Primary
#forward-addr: 8.8.4.4		# Google DNS Secondary
#forward-addr: 9.9.9.9		# Quad9 DNS

3. KeepAlived config Primary Host (172.16.0.90)

Add this to /etc/keepalived/keepalived.conf You need to change some of the parameters. I use the pidfile to check if unbound is running in the chk_unbound script

! Configuration File for keepalived

global_defs {
   notification_email {
     [email protected]
   }
   notification_email_from [email protected]
   smtp_server SMTP_SERVER_IP OR FQDN
   smtp_connect_timeout 30
}

vrrp_script chk_unbound {
    script "/usr/sbin/pidof unbound"
    interval 5
}

vrrp_instance VI_1 {
    state MASTER
    interface ens192
    virtual_router_id 51
    priority 101
    advert_int 1
    authentication {
        auth_type AH
        auth_pass P@ssw0rd
    }
    unicast_src_ip 172.16.0.90
    unicast_peer {
        172.16.0.91
    }
    virtual_ipaddress {
        172.16.0.92 dev ens192 label ens192:vip
    }
    track_script {
        chk_unbound
    }
}

4. KeepAlived config Secondary Host (172.16.0.91)
! Configuration File for keepalived

global_defs {
   notification_email {
     [email protected]
   }
   notification_email_from [email protected]
   smtp_server SMTP_SERVER_IP or FQDN
   smtp_connect_timeout 30
}

vrrp_script chk_unbound {
    script "/usr/sbin/pidof unbound"
    interval 5
}

vrrp_instance VI_1 {
    state BACKUP
    interface ens192
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type AH
        auth_pass P@ssw0rd
    }
    unicast_src_ip 172.16.0.91
    unicast_peer {
        172.16.0.90
    }
    virtual_ipaddress {
        172.16.0.92 dev ens192 label ens192:vip
    }
    track_script {
        chk_unbound
    }
}
5. Enable and start KeepAlived
systemctl enable --now keepalived.service
6. Firewall

Create a firewall rule so the keepalived instances can communicate and get health status

firewall-cmd --add-rich-rule='rule protocol value="vrrp" accept' --permanent
firewall-cmd --reload