rss.png profile for ebal on Stack Exchange, a network of free, community-driven Q&A sites
Migrating to PowerDNS

A few years ago, I migrated from ICS Bind Authoritative Server to PowerDNS Authoritative Server.

Here was my configuration file:

# egrep -v '^$|#' /etc/pdns/pdns.conf 




Α quick reminder, a DNS server is running on tcp/udp port53.

I use dnsdist (a highly DNS-, DoS- and abuse-aware loadbalancer) in-front of my pdns-auth, so my configuration file has a small change:


instead of local-address, local-ipv6

You can also use pdns without dnsdist.

My named.conf looks like this:

# cat /etc/pdns/named.conf

zone "" IN {
    type master;
    file "/etc/pdns/var/";

So in just a few minutes of work, bind was no more.
You can read more on the subject here: Migrating to PowerDNS.

Converting from Bind zone files to SQLite3

PowerDNS has many features and many Backends. To use some of these features (like the HTTP API json/rest api for automation, I suggest converting to the sqlite3 backend, especially for personal or SOHO use. The PowerDNS documentation is really simple and straight-forward: SQLite3 backend


Install the generic sqlite3 backend.
On a CentOS machine type:

# yum -y install pdns-backend-sqlite


Create the directory in which we will build and store the sqlite database file:

# mkdir -pv /var/lib/pdns


You can find the initial sqlite3 schema here:


you can also review the sqlite3 database schema from github

If you cant find the schema.sqlite3.sql file, you can always download it from the web:

# curl -L -o /var/lib/pdns/schema.sqlite3.sql  \

Create the database

Time to create the database file:

# cat /usr/share/doc/pdns/schema.sqlite3.sql | sqlite3 /var/lib/pdns/pdns.db

Migrating from files

Now the difficult part:

# zone2sql --named-conf=/etc/pdns/named.conf -gsqlite | sqlite3 /var/lib/pdns/pdns.db

100% done
7 domains were fully parsed, containing 89 records

Migrating from files - an alternative way

If you have already switched to the generic sql backend on your powerdns auth setup, then you can use: pdnsutil load-zone command.

# pdnsutil load-zone /etc/pdns/var/ 

Mar 20 19:35:34 Reading random entropy from '/dev/urandom'
Creating ''


If you dont want to read error messages like the below:

sqlite needs to write extra files when writing to a db file

give your powerdns user permissions on the directory:

# chown -R pdns:pdns /var/lib/pdns


Last thing, make the appropriate changes on the pdns.conf file:

## launch=bind
## bind-config=/etc/pdns/named.conf


Reload Service

Restarting powerdns daemon:

# service pdns restart

Restarting PowerDNS authoritative nameserver: stopping and waiting..done
Starting PowerDNS authoritative nameserver: started


# dig @ -p 5353  -t soa +short 2018020107 14400 7200 1209600 86400


# dig -t soa +short 2018020107 14400 7200 1209600 86400


Using the API

Having a database as pdns backend, means that we can use the PowerDNS API.

Enable the API

In the pdns core configuration file: /etc/pdns/pdns.conf enable the API and dont forget to type a key.


The API key is used for authorization, by sending it through the http headers.

reload the service.

Testing API

Using curl :

# curl -s -H 'X-API-Key: 0123456789ABCDEF'

The output is in json format, so it is prefable to use jq

# curl -s -H 'X-API-Key: 0123456789ABCDEF' | jq .

    "zones_url": "/api/v1/servers/localhost/zones{/zone}",
    "version": "4.1.1",
    "url": "/api/v1/servers/localhost",
    "type": "Server",
    "id": "localhost",
    "daemon_type": "authoritative",
    "config_url": "/api/v1/servers/localhost/config{/config_setting}"

jq can also filter the output:

# curl -s -H 'X-API-Key: 0123456789ABCDEF' | jq .[].version


Getting the entire zone from the database and view all the Resource Records - sets:

# curl -s -H 'X-API-Key: 0123456789ABCDEF'

or just getting the serial:

# curl -s -H 'X-API-Key: 0123456789ABCDEF' | \
  jq .serial


or getting the content of SOA type:

# curl -s -H 'X-API-Key: 0123456789ABCDEF' | \
  jq '.rrsets[] | select( .type | contains("SOA")).records[].content '

" 2018020107 14400 7200 1209600 86400"


Creating or updating records is also trivial.
Create the Resource Record set in json format:

# cat > /tmp/test.text <<EOF
    "rrsets": [
            "name": "",
            "type": "TXT",
            "ttl": 86400,
            "changetype": "REPLACE",
            "records": [
                    "content": ""Test, this is a test ! "",
                    "disabled": false


and use the http Patch method to send it through the API:

# curl -s -X PATCH -H 'X-API-Key: 0123456789ABCDEF' --data @/tmp/test.text \ | jq . 

Verify Record

We can use dig internal:

# dig -t TXT @ -p 5353 +short
"Test, this is a test ! "

querying public dns servers:

$ dig txt +short @
"Test, this is a test ! "

$ dig txt +short @
"Test, this is a test ! "

or via the api:

# curl -s -H 'X-API-Key: 0123456789ABCDEF' | \
   jq '.rrsets[].records[] | select (.content | contains("test")).content'

""Test, this is a test ! ""

That’s it.

Tag(s): powerdns, sqlite, api