Running PowerDNS and PowerDNS Admin in Docker Containers

Posted on 166 views

PowerDNS is a server software written in C++ to provide both recursive and authoritative DNS services. The Recursor DNS does not have any knowledge of domains and consults the authoritative servers to provide answers to questions directed to it while the Authoritative DNS server answers questions on domains it has knowledge about and ignores queries about domains it doesn’t know about. Both products are provided separately but in most cases combined to work seamlessly.

PowerDNS was developed in the late 90s and became an open-source tool in 2002. PowerDNS has been deployed throughout the world to become the best DNS server. The rapid growth of PowerDNS is mainly due to the following features offered.

  • It offers very high domain resolution performance.
  • Offers Open Source workhorses: Authoritative Server, dnsdist and Recursor
  • It provides a lot of statistics during its operation which not only helps to determine the scalability of an installation but also spotting problems.
  • Supports innumerable backends ranging from simple zonefiles to relational databases and load balancing/failover algorithms.
  • Has improved security features.

To make management of the PowerDNS server easier, a tool known as PowerDNS Admin was introduced. This is a web admin interface that allows one to create and manage DNS zones on the PowerDNS server. It offers the following features:

  • Support Google / Github / Azure / OpenID OAuth
  • User activity logging
  • Multiple domain management
  • Domain templates
  • DynDNS 2 protocol support
  • Support Local DB / SAML / LDAP / Active Directory user authentication
  • Edit IPv6 PTRs using IPv6 addresses directly (no more editing of literal addresses)
  • Full IDN/Punycode support
  • Limited API for manipulating zones and records
  • Dashboard and pdns service statistics
  • Support Two-factor authentication (TOTP)
  • User access management based on domain

This guide provides the required steps to run PowerDNS and PowerDNS Admin in Docker Containers. There are other ways to run PowerDNS and PowerDNS Admin such as:

These methods contain quite a number of steps. Using Docker is the easiest of them all.

Step 1 – Prepare your Server

Begin by preparing your server for the installation. There are packages required that can be installed as below:

## On RHEL/CentOS/RockyLinux 8
sudo yum update
sudo yum install curl vim

## On Debian/Ubuntu
sudo apt update && sudo apt upgrade
sudo apt install curl vim

## On Fedora
sudo dnf update
sudo dnf -y install curl vim

Disable system resolved service which runs on port 53 and provides network name resolution used to load applications. This port will be used by PowerDNS instead.

sudo systemctl stop systemd-resolved
sudo systemctl disable systemd-resolved

Remove the symbolic link.

$ ls -lh /etc/resolv.conf 
-rw-r--r-- 1 root root 49 Feb 23 04:53 /etc/resolv.conf
$ sudo unlink /etc/resolv.conf

Now update the resolve conf.

echo "nameserver" | sudo tee /etc/resolv.conf

Step 2 – Install Docker and Docker-Compose on Linux

I assume that you already have Docker Engine is installed on your system, otherwise install Docker using the dedicated guide below.

Before you proceed, ensure that your system user is added to the docker group.

sudo usermod -aG docker $USER
newgrp docker

Start and enable Docker.

sudo systemctl start docker && sudo systemctl enable docker

You may also need Docker-compose installed to be able to run the container using the docker-compose YAML file. Install Docker Compose using the below commands:

First, download the script using cURL.

curl -s | grep browser_download_url  | grep docker-compose-linux-x86_64 | cut -d '"' -f 4 | wget -qi -

Make it executable and move it to your path using the commands:

chmod +x docker-compose-linux-x86_64
sudo mv docker-compose-linux-x86_64 /usr/local/bin/docker-compose

Verify the installation.

$ docker-compose version
Docker Compose version v2.2.3

Step 3 – Create a Persistent Volume for the PowerDNS Container.

Create a persistent volume for PowerDNS with the right permissions as below.

sudo mkdir /pda-mysql
sudo chmod 777 /pda-mysql

The above volume will be used to persist the database and configurations. On Rhel-based systems, you need to set SELinux in permissive mode for the Path to be accessible.

sudo setenforce 0
sudo sed -i 's/^SELINUX=.*/SELINUX=permissive/g' /etc/selinux/config

Step 4 – Run PowerDNS and PowerDNS Admin in Docker Containers

There are two options on how to proceed:

  • Directly from Docker Hub
  • Using Docker-Compose

Option 1 – From Docker Hub

This is so simple since few configurations are required. The PowerDNS Docker image consists of 4 images namely:

  • pdns-mysql – the PowerDNS server configurable with MySQL backend.
  • pdns-recursor– contains completely configurable PowerDNS 4.x recursor
  • pdns-admin-uwsgi – web app, written in Flask, for managing PowerDNS servers
  • pdns-admin-static – fronted (nginx)

We will run each of these containers and link them to each other.

  • The Database Container.

We will use MariaDB as the database container with the PowerDNS database created as below.

docker run --detach --name mariadb \
      -e MYSQL_DATABASE=pdns \
      -e MYSQL_USER=pdns \
      -e MYSQL_PASSWORD=mypdns \
      -v /pda-mysql:/var/lib/mysql \
  • The PowerDNS master Container.

We will use the PowerDNS server configurable with MySQL backend linked to the database as below.

docker run -d -p 53:53 -p 53:53/udp --name pdns-master \
  --hostname pdns\
  --domainname \
 --link mariadb:mysql \
  -e PDNS_master=yes \
  -e PDNS_api=yes \
  -e PDNS_api_key=secret \
  -e PDNS_webserver=yes \
  -e PDNS_webserver-allow-from=,,, \
  -e PDNS_webserver_address= \
  -e PDNS_webserver_password=secret2 \
  -e PDNS_version_string=anonymous \
  -e PDNS_default_ttl=1500 \
  -e PDNS_allow_notify_from= \
  -e PDNS_allow_axfr_ips= \

Here we allow the API to be accessible from several IP addresses to avoid the error “connection Refused by peer” or error 400 when creating domains.

  • The PowerDNS Admin Container.
docker run -d --name pdns-admin-uwsgi \
  -p 9494:9494 \
  --link mariadb:mysql --link pdns-master:pdns \
  • The PowerDNS Admin service Container

Now expose the service using the pdns-admin-static container to expose the service.

docker run -d -p 8080:80 --name pdns-admin-static \
  --link pdns-admin-uwsgi:pdns-admin-uwsgi \

Now you should have all four containers up and running:

$ docker ps
CONTAINER ID   IMAGE                        COMMAND                  CREATED          STATUS          PORTS                                                                  NAMES
b71e4e3dcdcb   pschiffe/pdns-admin-static   "/usr/sbin/nginx -g …"   7 seconds ago    Up 5 seconds>80/tcp, :::8080->80/tcp                                  pdns-admin-static
99332d2b4322   pschiffe/pdns-admin-uwsgi    "/docker-entrypoint.…"   2 minutes ago    Up 2 minutes>9494/tcp, :::9494->9494/tcp                              pdns-admin-uwsgi
0b2cfb575481   pschiffe/pdns-mysql          "/docker-entrypoint.…"   3 minutes ago    Up 3 minutes>53/tcp,>53/udp, :::53->53/tcp, :::53->53/udp   pdns-master
f622128deb1d   mariadb:latest               "docker-entrypoint.s…"   10 minutes ago   Up 10 minutes   3306/tcp                                                               mariadb

At this point, the PowerDNS Admin web UI should be accessible on port 8080

Option 2 – Using Docker-Compose

With this method, all the variables are defined in a docker-compose file. Create the docker-conpose.yml file.

vim docker-compose.yml

In the file, you need to add the below lines.

version: '2'

    image: mariadb:latest
      - MYSQL_DATABASE=powerdnsadmin
      - MYSQL_USER=pdns 
      - MYSQL_PASSWORD=mypdns
      - 3306:3306 
    restart: always
      - /pda-mysql:/var/lib/mysql
    #build: pdns
    image: pschiffe/pdns-mysql
    hostname: pdns
    restart: always
      - db
      - "db:mysql"
      - "53:53"
      - "53:53/udp"
      - "8081:8081"
      - PDNS_gmysql_host=db
      - PDNS_gmysql_port=3306
      - PDNS_gmysql_user=pdns
      - PDNS_gmysql_dbname=powerdnsadmin
      - PDNS_gmysql_password=mypdns
      - PDNS_master=yes 
      - PDNS_api=yes
      - PDNS_api_key=secret 
      - PDNSCONF_API_KEY=secret 
      - PDNS_webserver=yes 
      - PDNS_webserver-allow-from=,,, 
      - PDNS_webserver_address= 
      - PDNS_webserver_password=secret2 
      - PDNS_version_string=anonymous 
      - PDNS_default_ttl=1500 
      - PDNS_allow_notify_from= 
      - PDNS_allow_axfr_ips= 

    image: ngoduykhanh/powerdns-admin:latest
    container_name: powerdns_admin
      - "8080:80"
      - db
    restart: always
      - db:mysql
      - pdns:pdns
      driver: json-file
        max-size: 50m
      - SQLALCHEMY_DATABASE_URI=mysql://pdns:[email protected]/powerdnsadmin

In the above file, we have the below sections:

  • pdns for the DNS server. Remeber to set a PDNS_api_key to be used to connect to the PDNS dashboard.
  • db database for powerDns. It will include tables for domains, zones, etc
  • pdns-mysql DNS server configurable with MySQL database
  • web_app admin web UI for interaction with powerdns

Run the container using the command:

docker-compose up -d

Check if the containers are running:

$ docker ps
CONTAINER ID   IMAGE                               COMMAND                  CREATED          STATUS                            PORTS                                                                                                             NAMES
7c5761e3d2a2   ngoduykhanh/powerdns-admin:latest   " gunic…"   10 seconds ago   Up 7 seconds (health: starting)>80/tcp, :::8080->80/tcp                                                                             powerdns_admin
ebf3ff118c72   pschiffe/pdns-mysql                 "/docker-entrypoint.…"   10 seconds ago   Up 8 seconds            >53/tcp, :::53->53/tcp,>8081/tcp,>53/udp, :::8081->8081/tcp, :::53->53/udp   thor-pdns-1
9ede175d6ae0   mariadb:latest                      "docker-entrypoint.s…"   11 seconds ago   Up 9 seconds            >3306/tcp, :::3306->3306/tcp                                                                         thor-db-1

Here the PowerDNS service is available on port 8080

Step 5 – Access the PowerDNS Admin Web UI

Now you should be able to access the Web UI using the port set i.e http://IP_address:8080


Create a user for PowerDNS.


Login using the created user.


Now access the dashboard by providing the URL http://pdns:8081/ and API Key in the YAML secret and update


Now the error will disappear, proceed to the dashboard.


There are no domains at the moment, we need to add new domains. Let’s create a sample by clicking on +New Domain tab.


Enter the domain name you want to add, you can as well select the template to use for configuration from the templates list, and submit. Navigate to the dashboard and you will have your domain added as below.


Records can be added to the domain by clicking on it. Set the name of the record, save and apply changes.


PowerDNS admin web UI makes it easy to manage the PowerDNS Admin. Here there are many other configurations you can make such as editing the domain templates, removing domains, managing user accounts e.t.c. View the history of activities performed on the server.


Step 6 – Secure PowerDNS Web with SSL

You can as well issue SSL certificates in order to access the web UI using HTTPS which is more secure. In this guide, we will issue self-signed Certificates using OpenSSL. Ensure openssl is installed before proceeding as below.

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout pdnsadmin_ssl.key -out pdnsadmin_ssl.crt

Provide the required details to create the certificates. Once created, move them to the /etc/ssl/certs directory.

sudo cp pdnsadmin_ssl.crt /etc/ssl/certs/pdnsadmin_ssl.crt
sudo mkdir -p /etc/ssl/private/
sudo cp pdnsadmin_ssl.key /etc/ssl/private/pdnsadmin_ssl.key

Now install the Nginx web server.

##On RHEL/CentOS/Rocky Linux 8
sudo yum install nginx

##On Debian/Ubuntu
sudo apt install nginx

Create a PowerDNS admin Nginx conf file. On a Rhel-based system, the conf will be under /etc/nginx/conf.d/ as below

sudo vim /etc/nginx/conf.d/pdnsadmin.conf

Now add the lines below replacing the server name.

        listen       443 ssl http2 default_server;
        listen       [::]:443 ssl http2 default_server;
        root         /usr/share/nginx/html;

        ssl_certificate /etc/ssl/certs/pdnsadmin_ssl.crt;
        ssl_certificate_key /etc/ssl/private/pdnsadmin_ssl.key;
	ssl_protocols TLSv1.2 TLSv1.1 TLSv1;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / 
       proxy_pass http://localhost:8080/;
            index  index.html index.htm;

        error_page 404 /404.html;
            location = /40x.html 

        error_page 500 502 503 504 /50x.html;
            location = /50x.html 

Save the file and set the appropriate permissions.

# CentOS / RHEL / Fedora
sudo chown nginx:nginx /etc/nginx/conf.d/pdnsadmin.conf
sudo chmod 755 /etc/nginx/conf.d/pdnsadmin.conf

# Debian / Ubuntu
sudo chown www-data:www-data /etc/nginx/conf.d/pdnsadmin.conf
sudo chmod 755 /etc/nginx/conf.d/pdnsadmin.conf

Start and enable Nginx.

sudo systemctl start nginx
sudo systemctl enable nginx

You may need to allow HTTPS through the firewall.

sudo firewall-cmd --add-service=http --permanent
sudo firewall-cmd --add-service=https --permanent
sudo firewall-cmd --reload

Now access PowerDNS admin web via HTTPS with the URL https://IP_Address or https://domain_name



That marks the end of this guide on how to run PowerDNS and PowerDNS Admin in Docker Containers. I hope this was significant.


Gravatar Image
A systems engineer with excellent skills in systems administration, cloud computing, systems deployment, virtualization, containers, and a certified ethical hacker.