Master‑Slave DNS Cluster on WHM: PowerDNS Step‑by‑Step Guide
Master‑slave PowerDNS on AlmaLinux WHM servers centralizes DNS zones, automates AXFR replication, and syncs with cPanel for reliable, scalable DNS management.
7 min read
Managing multiple WHM (cPanel) servers offers significant flexibility, but it introduces a critical challenge: maintaining consistent DNS records across every node. A master-slave DNS cluster using PowerDNS solves this by centralizing zone data on a primary server while automatically replicating it to secondary nodes. This guide walks you through setting up a PowerDNS master-slave architecture across several WHM nodes, using free, open-source components available on AlmaLinux 9 (or other RHEL-compatible distributions).
1. Prerequisites and Planning
Before beginning, ensure your environment meets the following requirements:
WHM Version: Any recent cPanel/WHM release. Note that native DNS zone files are typically stored in /var/named.
Operating System: AlmaLinux 9 (or Rocky 9 / RHEL 9). All commands in this guide use dnf.
Network Access: Each WHM node must be able to reach the others over TCP/53 (DNS) and TCP/8081 (PowerDNS API, if enabled).
Root Access: Required to install packages, edit configuration files, and restart services.
Backup: Take a full backup of /var/named and your database on every node before making changes.
In this setup, we will configure:
PowerDNS Authoritative Server (Master) on WHM Node A.
PowerDNS Authoritative Server (Slave) on WHM Node B (and optionally others).
PowerDNS Recursor (optional) for internal DNS resolution.
cPanel Integration to ensure new zones created in WHM are synchronized to PowerDNS.
2. Install PowerDNS Authoritative Server
PowerDNS provides two main packages for this setup: pdns (the daemon) and pdns-backend-mysql (the database connector). Since cPanel stores zone data in MySQL, we will use the MySQL backend on all nodes.
AlmaLinux 9 (dnf) – Master and Slave Nodes
# Install PowerDNS and the MySQL backend
dnf install -y pdns pdns-backend-mysql
# Enable the service to start on boot
systemctl enable pdns
dnf install -y pdns pdns-backend-mysql: Installs the authoritative daemon and the MySQL connector.
systemctl enable pdns: Ensures the service starts automatically after a reboot.
3. Configure the MySQL Backend
cPanel runs its own MySQL server (often referred to as MySQL or MariaDB depending on the version). We will create a dedicated database and user for PowerDNS to store and retrieve zone data.
Step 1: Create Database and User (Run on Master Node)
# Log in to MySQL as root
mysql -u root -p
# Inside the MySQL prompt:
CREATE DATABASE powerdns;
GRANT ALL PRIVILEGES ON powerdns.* TO 'pdns'@'%' IDENTIFIED BY 'StrongPasswordHere';
FLUSH PRIVILEGES;
EXIT;
Replace StrongPasswordHere with a secure, unique password. The '%' host wildcard allows slave nodes to connect from any IP, though you should restrict this to specific slave IPs in production environments for better security.
Step 2: Import the PowerDNS Schema
We need to populate the new database with the required table structures.
# Download the official schema (ensure it matches your PowerDNS version)
curl -O https://raw.githubusercontent.com/PowerDNS/pdns/master/modules/gmysqlbackend/schema.mysql.sql
# Import the schema into the powerdns database
mysql -u pdns -pStrongPasswordHere powerdns < schema.mysql.sql
Step 3: Configure PowerDNS on the Master
Edit the main configuration file:
sudo nano /etc/pdns/pdns.conf
Add or update the following directives:
launch=gmysql
gmysql-host=127.0.0.1
gmysql-user=pdns
gmysql-password=StrongPasswordHere
gmysql-dbname=powerdns
# Enable zone transfers
allow-axfr-ips=10.0.0.0/8,192.168.0.0/16 # Adjust to your specific private network ranges
master=yes
Key directives explained:
launch=gmysql: Tells PowerDNS to use the MySQL backend.
allow-axfr-ips: Lists the IP ranges permitted to request full zone transfers (AXFR).
master=yes: Marks this instance as the primary source of truth for zone data.
Step 4: Configure PowerDNS on the Slave
On the slave node, edit /etc/pdns/pdns.conf. The key difference is that the slave points to the master's MySQL server to share the same zone data.
launch=gmysql
gmysql-host=10.0.0.1 # IP address of the Master Node's MySQL server
gmysql-user=pdns
gmysql-password=StrongPasswordHere
gmysql-dbname=powerdns
# Slave-specific options
slave=yes
master=yes # Keep master=yes to allow outgoing AXFR requests if needed
Note: By pointing gmysql-host to the master, both nodes read from the same database, ensuring consistency.
4. Enable Automatic Zone Transfers (AXFR)
PowerDNS uses the standard DNS AXFR protocol to synchronize zones. We must ensure the master permits transfers to the slaves, and the slaves know where to fetch data.
On the Master: Define Allowed AXFR IPs
Ensure allow-axfr-ips in the master configuration includes the IP addresses of all slave nodes. For stricter security, list specific IPs rather than broad ranges:
allow-axfr-ips=192.0.2.10,192.0.2.11
On the Slave: Permit AXFR from the Master
Add the master's IP to the slave's configuration to allow it to fetch zones:
allow-axfr-ips=10.0.0.1 # Master's IP address
Restart PowerDNS on All Nodes
systemctl restart pdns
systemctl status pdns # Verify the service is active (green checkmark)
5. Integrate PowerDNS with WHM/cPanel
cPanel traditionally uses BIND and stores zones in /var/named. It also updates MySQL tables (dnsrecords, named) when users modify records. To keep PowerDNS in sync with WHM changes, we use a connector script that periodically syncs these tables.
Step 1: Install the cPanel-PowerDNS Connector
Run the following on the Master Node (as root):
cd /usr/local/src
git clone https://github.com/PowerDNS/pdns-cpanel.git
cd pdns-cpanel
# Run the installer script (check the script contents before running if you prefer manual setup)
./install.sh
This script typically sets up a cron job to run every few minutes, reading the cPanel MySQL tables and updating PowerDNS accordingly.
Step 2: Verify the Connector
Manually trigger a sync to test the connection:
/usr/local/pdns-cpanel/sync.sh
# Check if zones are visible in PowerDNS
pdnsutil list-all-zones
If your domains managed in WHM appear in the list, the integration is working.
Step 3: Disable BIND to Avoid Conflicts
Since PowerDNS will now handle all DNS queries, you should disable the default BIND service to prevent port 53 conflicts and inconsistent data.
# Stop and disable BIND
systemctl stop named
systemctl disable named
# Ensure PowerDNS listens on all interfaces (port 53)
# Check if local-address is commented out or set to 127.0.0.1 in /etc/pdns/pdns.conf
sed -i 's/^#local-address=127.0.0.1/local-address=0.0.0.0/' /etc/pdns/pdns.conf
# Restart PowerDNS
systemctl restart pdns
WHM will continue to write zone data to MySQL, but PowerDNS will now serve the actual DNS queries.
6. Adding Additional Slave Nodes
To scale out, repeat the installation (Section 2) and configuration (Sections 3–4) on each new node. Ensure that:
gmysql-host points to the Master's MySQL IP.
The new node's IP is added to allow-axfr-ips on the Master.
The Master's IP is added to allow-axfr-ips on the new Slave.
Optional: Use the PowerDNS API for On-Demand Transfers
PowerDNS includes a RESTful API (default port 8081) that allows you to trigger immediate zone notifications, bypassing the wait time for the next automatic AXFR cycle.
# Add to /etc/pdns/pdns.conf on the Master
api=yes
api-key=SuperSecretKey
webserver=yes
webserver-address=0.0.0.0
webserver-port=8081
systemctl restart pdns
You can then force a notification to slaves from any node with:
curl -X POST -H "X-API-Key: SuperSecretKey" \
http://10.0.0.1:8081/api/v1/servers/localhost/zones/example.com/notify
7. Testing and Validation
Check Zone Presence: Run pdnsutil list-all-zones on both Master and Slave. The lists should match.
Query a Record:
dig @10.0.0.1 example.com A
dig @10.0.0.2 example.com A # Replace with your slave IP
Both should return identical answers.
Simulate a Change:
Add a new A record in WHM.
Wait for the cron sync (or trigger the API notify).
Run dig @slave-ip newhost.example.com A to confirm propagation.
Failover Test:
systemctl stop pdns # On the Master
Verify that the Slave continues to answer queries correctly.
If issues arise, check the PowerDNS logs (/var/log/pdns.log or journalctl -u pdns) and verify MySQL connectivity from the slaves to the master.
Conclusion
By leveraging PowerDNS's MySQL backend and cPanel's native database storage, you can build a reliable master-slave DNS cluster across multiple WHM nodes. This setup keeps zone data in a single source of truth, automates replication via AXFR, and scales easily as you add more servers. The optional API integration provides instant propagation for critical updates. Following these steps on your AlmaLinux-based WHM servers ensures a resilient DNS infrastructure capable of supporting your growing web portfolio.