PowerDNS Master Slave DNS Replication with MySQL backend

Written by - 11 comments

Published on - Listed in DNS PowerDNS Linux


This is the second article of an article series about PowerDNS. The previous article (PowerDNS Authoritative DNS Server 4.1 with MySQL backend on Ubuntu 18.04) covered the installation and basic configuration of a standalone PowerDNS server. 

As the title already reveals, this post is all about DNS Master-Slave replication. But first we need to understand what replication capabilities PowerDNS offers.

DNS Replication Modes

As you can read from the official documentation about DNS Modes of Operation, there are two operation (replication) modes. Let's start with the default (native) mode.

Native replication

When PowerDNS talks about "native" replication, it is meant that PowerDNS does no replication at all. It leaves all the data synchronization and replication to its backend, for example a MySQL database with the pdns-backend-mysql package installed.

Talking in terms of databases that means that PowerDNS expects the databases replicated/synced between the different nameservers.

Let's assume the following scenario: We have three nameservers ns1.example.com, ns2.example.com, ns3.example.com. NS1 is considered the primary nameserver and our master where DNS zone and record changes happens. NS2 and NS3 are slave nameservers being there for redundancy.

As PowerDNS is running with a MySQL backend, a classical MySQL Master-Slave-Replication can be configured where the changes on NS1's database are replicated to the databases on NS2 and NS3.

No configuration change is needed in PowerDNS. Due to the replicated data in the backend database, all three nameservers send the same query responses.

The following graphic should explain how the native replication works:

PowerDNS Native Replication with MySQL backend

Of course you need to monitor the native replication somehow. In this scenario the MySQL replication can be monitored with the monitoring plugin check_mysql_slavestatus.

Master replication

If you have been working with BIND in the past, this is what you would have expected as a DNS replication in the first place. The "Master" replication is the classical replication of DNS zones/records through the DNS protocol itself. The primary nameserver (aka DNS Master) sends a NOTIFY command via the DNS protocol (udp 53) to the slave servers of a domain/zone. The slave servers then initiate an AXFR command (zone transfer) and send it to the master server. If permitted, the master sends the zone records to the slaves.

It is important to understand what is deemed a slave or how PowerDNS defines a slave. Basically explained, PowerDNS sends the NOTIFY command to all servers found as a "NS" record within a zone (even itself). So in order to use a Master replication, make sure that all your slave DNS servers were added as NS records of your zone(s).

The following graphic explains how the master replication works:

PowerDNS DNS Master Replication with MySQL Backend

It is also possible to trigger an AXFR command on the slave servers without having received a NOTIFY first.

In this article the setup focuses on the latter method: Master Replication.

How to configure DNS Master Slave replication in PowerDNS

Based on the installation and configuration of PowerDNS in the previous article (PowerDNS Authoritative DNS Server 4.1 with MySQL backend on Ubuntu 18.04), the following changes need to be done in pdns.conf. The changes differ between the master node and the slave nodes.

Master config

There are two options which must be defined: allow-axfr-ips and master.

The allow-axfr-ips option tells PowerDNS which endpoints are allowed to initiate and receive zone transfers. And of course we need to allow our DNS slaves to do so. 

Let's assume that ns2.example.com runs on 192.168.250.153 and ns3.example.com runs on 192.168.250.253. These two IP's are explicitly allowed for zone transfers. You may also define full ranges, e.g. 192.168.250.0/24 in this case, but always make sure you restrict zone transfers to the bare minimum.

#################################
# allow-axfr-ips        Allow zonetransfers only to these subnets
#
# allow-axfr-ips=127.0.0.0/8,::1
allow-axfr-ips=192.168.250.153,192.168.250.253

The other setting is quite obviously the "master" parameter, but it can be easily forgotten (happened to me!). Set the value to "yes" so PowerDNS knows this DNS server is a master server.

#################################
# master        Act as a master
#
# master=no
master=yes

After these changes, restart PowerDNS

root@master:~# systemctl restart pdns

Slave config

On the slave servers there is only one mandatory setting in pdns.conf: set slave to yes so PowerDNS knows this server is a slave server. Additionally to that you may also want the slave server keep up to date with the master on its own, without waiting for a NOTIFY command, by using the slave-cycle-interval option.

#################################
# slave Act as a slave
#
# slave=no
slave=yes

#################################
# slave-cycle-interval Schedule slave freshness checks once every .. seconds
#
# slave-cycle-interval=60
slave-cycle-interval=60

Now something that could be forgotten easily is the "supermasters" table in the backend. As we have a MySQL database as pdns backend, the master server needs to be added into the backend config, too.

The data you insert into the supermasters table consists of three values:

  1. The IP address of the DNS master (192.168.250.53)
  2. The FQDN of the slave server (myself)
  3. The role which should be assigned, should be admin role

Be aware that each slave must have its own FQDN as second value. 

So on NS2:

mysql> insert into powerdns.supermasters values ('192.168.250.53', 'ns2.example.com', 'admin');

And on NS3:

mysql> insert into powerdns.supermasters values ('192.168.250.53', 'ns3.example.com', 'admin');

After these changes, restart PowerDNS:

root@slave:~# systemctl restart pdns

Testing the replication

When a new zone was added to the master server, nothing happens yet:

root@master:~# pdnsutil create-zone replicateme.dev
Creating empty zone 'replicateme.dev'

On the slave, the domain does not show up:

root@slave:~# pdns_control list-zones | grep replicateme
root@slave:~#

That's normal because the zone does not have NS entries (and therefore no slave servers) yet.

Let's add the NS entries for NS1 (the master itself) and NS2 (the first slave):

root@master:~# pdnsutil add-record replicateme.dev @ NS ns1.example.com
New rrset:
replicateme.dev. IN NS 3600 ns1.example.com

root@master:~# pdnsutil add-record replicateme.dev @ NS ns2.example.com
New rrset:
replicateme.dev. IN NS 3600 ns1.example.com
replicateme.dev. IN NS 3600 ns2.example.com

Nothing has happened on the slave server yet. We first need to increase the zone's serial and then send a notify:

root@master:~# pdnsutil increase-serial replicateme.dev
SOA serial for zone replicateme.dev set to 2019040101

root@master:~# pdns_control notify replicateme.dev
Added to queue

On the slave server, the following log entries appear:

Apr  1 12:00:10 slave pdns_server[19527]: Received NOTIFY for replicateme.dev from 192.168.250.53 for which we are not authoritative
Apr  1 12:00:10 slave pdns_server[19527]: Created new slave zone 'replicateme.dev' from supermaster 192.168.250.53
Apr  1 12:00:10 slave pdns_server[19527]: 1 slave domain needs checking, 0 queued for AXFR
Apr  1 12:00:10 slave pdns_server[19527]: Received serial number updates for 1 zone, had 0 timeouts
Apr  1 12:00:10 slave pdns_server[19527]: Domain 'replicateme.dev' is stale, master serial 2019040101, our serial 0
Apr  1 12:00:10 slave pdns_server[19527]: Initiating transfer of 'replicateme.dev' from remote '192.168.250.53'
Apr  1 12:00:10 slave pdns_server[19527]: Starting AXFR of 'replicateme.dev' from remote 192.168.250.53:53
Apr  1 12:00:10 slave pdns_server[19527]: AXFR started for 'replicateme.dev'
Apr  1 12:00:10 slave pdns_server[19527]: AXFR of 'replicateme.dev' from remote 192.168.250.53:53 done
Apr  1 12:00:10 slave pdns_server[19527]: Backend transaction started for 'replicateme.dev' storage
Apr  1 12:00:10 slave pdns_server[19527]: AXFR done for 'replicateme.dev', zone committed with serial number 2019040101

And the domain now shows up on the slave and it can be queried:

root@slave:~# pdns_control list-zones | grep replicateme
replicateme.dev.

root@slave:~# dig -t NS replicateme.dev @localhost +short
ns1.example.com.
ns2.example.com.

Next up

The next article in this series will explain how to install a modern user interface (Opera DNS UI) for PowerDNS. The link to the article will be posted here once completed.


Add a comment

Show form to leave a comment

Comments (newest first)

Sapar from wrote on Jan 6th, 2023:

I understand. I'll probably create some kind of cron or something if I cannot find another way, but the official documentation (this time here: https://doc.powerdns.com/authoritative/modes-of-operation.html - Primary operation) suggests (to my mind) that the primary does that all by itself:
"When operating as a master, PowerDNS sends out notifications of changes to slaves, which react to these notifications by querying PowerDNS to see if the zone changed, and transferring its contents if it has."
and
"To resolve this issue, PowerDNS tries multiple tactics to figure out the IP addresses of the slaves and notifies everybody. In contrived configurations, this may lead to duplicate notifications being sent out, which shouldn’t hurt."

Just putting it out there in case you do write a blog about it :)
Thanks for your input. This has been helpful!


ck from Switzerland wrote on Jan 6th, 2023:

Sapar, not sure out of my head where this setting is set but since PowerDNS 4.1 (and right now on PowerDNS 4.6) I got used to either use Opera PowerDNS UI or use scripts which run a notify at the end. Maybe there is indeed a way to automate this though but this is how I do it. Coming (and still using BIND), I got used to the manual reload/notify commands :-)
This kind of reminds me I should create a new blog post on newer PowerDNS versions but time is my enemy these days.


Sapar from wrote on Jan 6th, 2023:

@ck I thought that activating autoprimary would solve this though. https://doc.powerdns.com/authoritative/modes-of-operation.html#autoprimary-operation
It is not clear to me if I'm supposed to be adding autosecondary to the primary or to the secondary (one would think it's on the secondary only), but I've added it to both to no avail.

The supermasters table must have the right information, because manual notify does work (it didn't work before when I added the wrong IP) and the NS record also contains the slave/secondary IP (which can be resolved).

Indeed, I'm not using anything that triggers this automatically, but I expected it to do it automatically from what I've been reading on the internet. A rather daunting experience. Your site was one of the few sources which make some sense of that horrid official documentation :)


ck from Switzerland wrote on Jan 6th, 2023:

Sapar, if you are using the command line to update/add dns records in the master, you will have to run the NOTIFY manually. Yes, that is similar to BIND by the way. I am using the Powedns UI (from Opera) which triggers this via the PowerDNS API and therefore automates this.


Sapar from wrote on Jan 6th, 2023:

This works great in my case (I'm using postgresql), but the master (not changed into primary and secondary respectively) won't do the notifying automatically unfortunately. I'm not sure how I can automate this without having to manually run the notify command.


ck from Switzerland wrote on Jan 15th, 2022:

Hendra, the article was for PowerDNS 4.1, maybe there are additional settings needed for newer versions. See also comments from other users.
My guess would be that your slave servers dont recognize the master server. Maybe missing superserver entry if you use the same version 4.1?
I will upgrade PowerDNS in the coming weeks and will write a new article about it.


Hendra from Indonesia wrote on Jan 15th, 2022:

Thank for structured article, it is very helpful for me.

1. What command to show this : "On the slave server, the following log entries appear:"
2. I am using tcpdump -n 'host ip_host and port 53' and get " notify Refused*- 0/0/0 (27)"

Please guide some suggestions.


Nick from Collogne wrote on May 12th, 2021:

Future Tip.
Up from Version 4.5

superslave=yes

is deprecated and will be renamed to:

autosecondary=yes

see official doc: https://doc.powerdns.com/authoritative/settings.html#superslave


Nick from wrote on May 8th, 2021:

Ab from Powerdns 4.3 u must add another command to the slave server:
add:

superslave=yes


ck from Switzerland wrote on Jun 18th, 2020:

Frank, to my knowledge you only need to run the notify command with the domain name (example.com), without mentioning a slave server. PowerDNS looks up all NS records in the domain and sends a notify to all the servers being a nameserver: pdns_control notify example.com.


Frank from wrote on Jun 17th, 2020:

Hi, when I issue the command
pdns_control notify-host mydomain.dev ns.mydomain.local

I get
Unable to convert 'ns.mydomain.local' to an IP address

I also added the ip in /etc/hosts
192.168.4.8 ns.mydomain.local


RSS feed

Blog Tags:

  AWS   Android   Ansible   Apache   Apple   Atlassian   BSD   Backup   Bash   Bluecoat   CMS   Chef   Cloud   Coding   Consul   Containers   CouchDB   DB   DNS   Database   Databases   Docker   ELK   Elasticsearch   Filebeat   FreeBSD   Galera   Git   GlusterFS   Grafana   Graphics   HAProxy   HTML   Hacks   Hardware   Icinga   Influx   Internet   Java   KVM   Kibana   Kodi   Kubernetes   LVM   LXC   Linux   Logstash   Mac   Macintosh   Mail   MariaDB   Minio   MongoDB   Monitoring   Multimedia   MySQL   NFS   Nagios   Network   Nginx   OSSEC   OTRS   Office   PGSQL   PHP   Perl   Personal   PostgreSQL   Postgres   PowerDNS   Proxmox   Proxy   Python   Rancher   Rant   Redis   Roundcube   SSL   Samba   Seafile   Security   Shell   SmartOS   Solaris   Surveillance   Systemd   TLS   Tomcat   Ubuntu   Unix   VMWare   VMware   Varnish   Virtualization   Windows   Wireless   Wordpress   Wyse   ZFS   Zoneminder