In this tutorial, we’ll walk you through the process of configuring high availability DNS servers for your Control Web Panel (CWP) using two bash scripts. This setup ensures redundancy and reliability for your DNS infrastructure, improving overall system availability.

Environment Details

Before we begin, let’s review the environment details:

  • CWP Server: Rocky Linux 8 (Hostname: cwpserver01.domain.local)
  • DNS Cluster Servers: Rocky Linux 9 (Hostnames: dns01.domain.local and dns02.domain.local)

Step 1: Generating SSH Keys and Copying to DNS Servers

First, we need to generate SSH keys on the CWP server and copy them to the DNS cluster servers. This will facilitate secure communication between the servers.

# Generate SSH keys on CWP server
ssh-keygen -t rsa

# Copy SSH keys to Rocky Linux 9 BIND servers
ssh-copy-id -i /root/.ssh/id_rsa.pub root@dns01.domain.local
ssh-copy-id -i /root/.ssh/id_rsa.pub root@dns02.domain.local

Replace dns01.domain.local and dns02.domain.local with the actual hostnames or IP addresses of your Rocky Linux 9 BIND servers.

Step 2: Configuring High Availability DNS Servers

Next, we’ll configure high availability for your DNS servers using two bash scripts. Let’s delve into the details of each script and its functionality.

Script 1: Synchronizing DNS Records and Reloading BIND

Save the following script as /opt/dns/dns-sync.sh on your CWP server and make it executable with .

chmod +x /opt/dns/dns-sync.sh

First Script:

#!/bin/bash

# Define the remote paths for DNS zones on Rocky Linux servers
REMOTE_USER1="root"  # Replace with your Rocky Linux SSH username for dns01
REMOTE_USER2="root"  # Replace with your Rocky Linux SSH username for dns02
REMOTE_SERVER1="dns01.domain.local"
REMOTE_SERVER2="dns02.domain.local"
REMOTE_PATH="/var/named/"  # Remote path for named
REMOTE_SCRIPT="/opt/dns/generate_named_conf_reload.sh"  # Remote script path

echo "Starting the script to sync zone files to remote servers..."

# Sync zone files to the first Rocky Linux server
echo "Syncing zone files to ${REMOTE_SERVER1}..."
if timeout 5s sudo rsync -avz --delete /var/named/ ${REMOTE_USER1}@${REMOTE_SERVER1}:${REMOTE_PATH}/; then
    echo "Sync to ${REMOTE_SERVER1} completed successfully."
else
    echo "Sync to ${REMOTE_SERVER1} failed. Moving on to the next server."
fi

# Sync zone files to the second Rocky Linux server
echo "Syncing zone files to ${REMOTE_SERVER2}..."
if timeout 5s sudo rsync -avz --delete /var/named/ ${REMOTE_USER2}@${REMOTE_SERVER2}:${REMOTE_PATH}/; then
    echo "Sync to ${REMOTE_SERVER2} completed successfully."
else
    echo "Sync to ${REMOTE_SERVER2} failed. Moving on to the next server."
fi

# Determine if the current minute is odd or even
current_minute=$(date +%M)
if ((current_minute % 2 != 0)); then
    # Odd minute - execute script on dns01 and reload BIND
    echo "Executing script and reloading BIND on ${REMOTE_SERVER1}..."
    if timeout 5s ssh ${REMOTE_USER1}@${REMOTE_SERVER1} "${REMOTE_SCRIPT}"; then
        echo "Script execution on ${REMOTE_SERVER1} completed successfully."
    else
        echo "Script execution on ${REMOTE_SERVER1} failed."
    fi
else
    # Even minute - execute script on dns02 and reload BIND
    echo "Executing script and reloading BIND on ${REMOTE_SERVER2}..."
    if timeout 5s ssh ${REMOTE_USER2}@${REMOTE_SERVER2} "${REMOTE_SCRIPT}"; then
        echo "Script execution on ${REMOTE_SERVER2} completed successfully."
    else
        echo "Script execution on ${REMOTE_SERVER2} failed."
    fi
fi

echo "Sync completed successfully."

Explanation of Script 1 Logic

  • Synchronization: The script synchronizes DNS zone files from the CWP server to the remote BIND servers (dns01 and dns02) using rsync. It ensures that any changes made on the CWP server are replicated on the DNS servers.
  • Odd-Even Logic: The script utilizes the parity of the current minute to determine which DNS server should execute the remote script (REMOTE_SCRIPT) to reload the BIND service. This alternates between the primary (dns01) and secondary (dns02) servers, distributing the workload evenly.

Using Odd-Even Logic for BIND Service Reload

In the provided script (dns-sync.sh), there’s a section that determines whether the current minute is odd or even using the date +%M command. This logic serves a crucial purpose in ensuring seamless and uninterrupted service during DNS zone file synchronization.

Purpose of Odd-Even Logic

  • Load Distribution: By alternating the execution of the remote script (REMOTE_SCRIPT) between the primary and secondary DNS servers based on the parity of the current minute, the script distributes the workload evenly across both servers. This prevents a single server from bearing the burden of frequent BIND service reloads, which could potentially impact performance.
  • High Availability: In a high availability setup, it’s essential to ensure that critical services like BIND are always available. By reloading the BIND service alternately between the primary and secondary servers, the script minimizes the risk of downtime during updates or synchronization activities. If one server is undergoing maintenance or experiencing issues, the other server can continue to serve DNS requests without interruption.

Example Scenario

  • Odd Minute: When the current minute is odd, the script executes the remote script (REMOTE_SCRIPT) on the primary DNS server (REMOTE_SERVER1) to reload the BIND service. This ensures that any changes or updates to the DNS zone files take effect on the primary server, and DNS resolution remains uninterrupted for clients querying this server.
  • Even Minute: Conversely, when the current minute is even, the script executes the remote script on the secondary DNS server (REMOTE_SERVER2). This ensures that the secondary server stays synchronized with the primary server and is ready to take over DNS resolution if needed, providing redundancy and fault tolerance.

Conclusion

In summary, the odd-even logic employed in the script helps maintain a balanced workload distribution and ensures high availability of the DNS service across multiple servers in a cluster. By carefully orchestrating the execution of the BIND service reloads, the script optimizes performance and resilience in the DNS infrastructure.

Script 2: Generating named.conf and Reloading BIND

Save the following script as /opt/dns/generate_named_conf_reload.sh on both DNS servers (Rocky Linux 9) and make it executable with following command:

chmod +x /opt/dns/generate_named_conf_reload.sh

Second Script:

#!/bin/bash

# Directory containing .db files
DB_DIR="/var/named"
# Location of named.conf
NAMED_CONF="/etc/named.conf"
# Temp file to store existing zones
TMP_FILE="/tmp/existing_zones.txt"

echo "Starting the script to generate named.conf and reload BIND..."

# Generate list of existing zones in named.conf
echo "Generating a list of existing zones in named.conf..."
grep "zone " "$NAMED_CONF" | awk -F\" '{print $2}' > "$TMP_FILE"
echo "Existing zones list generated."

# Check if any new .db files are present
echo "Checking for new .db files in $DB_DIR..."
NEW_ZONES=$(find "$DB_DIR" -name "*.db" -type f)
for file in $NEW_ZONES; do
    zone=$(basename "$file" .db)
    # Check if the zone is already included in named.conf
    if ! grep -q "$zone" "$TMP_FILE"; then
        # Add zone to named.conf
        echo "Adding zone $zone from $file to named.conf..."
        echo "zone \"$zone\" {
            type master;
            file \"$file\";
        };" >> "$NAMED_CONF"
        echo "Zone $zone added to named.conf."
    fi
done

# Check if any .db files have been removed
echo "Checking for removed .db files..."
while IFS= read -r existing_zone; do
    db_file="$DB_DIR/$existing_zone.db"
    if [ ! -f "$db_file" ]; then
        # Remove zone from named.conf
        echo "Removing zone $existing_zone from named.conf..."
        sed -i "/zone \"$existing_zone\" {/,/};/d" "$NAMED_CONF"
        echo "Zone $existing_zone removed from named.conf."
    fi
done < "$TMP_FILE"

# Remove temporary file
echo "Cleaning up temporary files..."
rm -f "$TMP_FILE"
echo "Temporary files cleaned up."

# Check BIND configuration
echo "Checking BIND configuration..."
if named-checkconf "$NAMED_CONF"; then
    # Reload BIND
    echo "Reloading BIND..."
    if systemctl reload named; then
        echo "BIND reloaded successfully."
    else
        echo "Error: Failed to reload BIND."
        exit 1
    fi
else
    echo "Error: BIND configuration check failed."
    exit 1
fi

echo "Script execution completed."

Explanation of Script 2 Logic

  • Named.conf Generation: The script generates the named.conf file by dynamically adding or removing zone configurations based on the presence of .db files in the specified directory ($DB_DIR). This ensures that the BIND service is aware of all DNS zones and their configurations.
  • Configuration Check and Reload: After updating the named.conf file, the script checks the BIND configuration for errors using named-checkconf. If the configuration is valid, it reloads the BIND service using systemctl reload named, ensuring that changes to DNS configurations take effect immediately.

Purpose of Script 2 Tasks

  • Generating named.conf: The script first generates a list of existing zones in named.conf. It then checks for new .db files and adds any new zones to named.conf. Similarly, it checks for removed .db files and removes corresponding zones from named.conf, ensuring that the configuration stays up to date.
  • Checking BIND Configuration and Reloading: After updating named.conf, the script checks the BIND configuration for errors using named-checkconf. If the configuration is valid, it reloads the BIND service to apply the changes. This ensures that the DNS service remains consistent and operational.

Additional Instructions

Line Ending Correction

When copying and pasting the scripts from Windows to Linux environments, they may have incorrect line endings, which can cause errors when executing the scripts. To ensure proper functionality, follow these steps:

  1. On CWP Server (Rocky Linux 8):
    • Run the following command to correct the line endings for the synchronization script: dos2unix /opt/dns/dns-sync.sh
  2. On DNS Servers (Rocky Linux 9):
    • Run the following command on each DNS server to correct the line endings for the generation and reload script:
      dos2unix /opt/dns/generate_named_conf_reload.sh

This will ensure that both scripts are formatted correctly for execution on their respective servers.

Final Steps

  • On CWP Server (Rocky Linux 8):
    • Add the dns-sync.sh script to the root user’s crontab to ensure it runs periodically and keeps your DNS servers synchronized and updated. sudo crontab -e Then add the following line at the end of the file
    */5 * * * * /opt/dns/dns-sync.sh >> /var/log/dns-sync.log 2>&1
    This will run the synchronization script (dns-sync.sh) every 5 minutes. Logs will be saved in /var/log/ for monitoring and troubleshooting.
  • On DNS Servers (Rocky Linux 9):
    • Run the generate_named_conf_reload.sh script to generate named.conf and reload BIND as needed. This script should already be set up to run as part of the synchronization process initiated by dns-sync.sh.