Skip to content
⚠️ Warning: Extraordinary electrical maintenance – Scheduled shutdown of the Cloud garr-ct1 region (Catania) from 22 to 29 July 2025. For more details, please read the maintenance notice.

Install Authoritative DNS

This recipe, which largely references existing documentation, guides you to the installation of a PowerDNS Authoritative DNS server and of its PowerDNS-admin GUI frontend. The PowerDNS server is backed by a MySQL/MariaDB database.

The recipe is intended for such cases where a minimal DNS service is needed. For this reason, the DNS server (as well as the backend MySQL/MariaDB database ) and its GUI will be installed on the same virtual machine.

PowerDNS version 4.X will be installed, which acts as a pure DNS authoritative server. You may also consider installing a PowerDNS recursor, but this part is not covered here and is left as an exercise.

The recipe assumes CentOS operating system: for other operating systems, refer to the relevant official pages and change commands accordingly.

Out of the many possible alternatives for the management GUI, I abandoned the glorious PowerAdmin (still available at https://www.poweradmin.org/), which served me so well until today, as it seems not to be maintained since a long time. On the other hand, PowerDNS-Admin seems to have a rather large and lively community behind. One benefit of this latter product is that it no longer requires direct access to the MySQL database, as it interacts via PowerDNS API.

Prerequisites

Configure firewall

In order to protect the virtual machine running the DNS server, you need to properly configure your firewall. If the virtual machine is created within an OpenStack tenant, I strongly advice to create a dedicated Security Group containing the following exceptions:

  • allow UDP access to port 53 (from the Universe, if this DNS is going to be authoritative)
  • allow TCP access to port 53 (from the Universe, if this DNS is going to be authoritative)
  • allow TCP access to port 8181 (PowerDNS webserver GUI) from trusted hosts/networks
  • allow TCP access to port 9191 (PowerDNS-Admin management GUI) from trusted hosts/networks
  • allow TCP access to port 22 (SSH) from trusted hosts/networks

Moreover, I also find it convenient to add ICMP access from 0.0.0.0.

MySQL server

Install the MariaDB server, configure it, update and reboot:

yum install epel-release
yum install mariadb-server
systemctl start mariadb
systemctl enable mariadb
systemctl status mariadb
mysql_secure_installation # initially, root password is blank, during the
                          # command execution you can set it to something sensible
yum update
reboot

Ansible

Install Ansible:

yum install epel-release
yum install ansible

Create Ansible user, with sudo privileges:

  • create a group for ansible, edit file /etc/group and add a line like:
  groupadd --gid 22222 ansible
  • create user ansible::
  useradd --create-home --gid 22222 --uid 22222 ansible
  • add user to sudoers, touch file /etc/sudoers.d/ansible with content:
  Defaults:ansible     !requiretty
  ansible ALL = (root) NOPASSWD:ALL

PowerDNS installation and setup

PowerDNS is managed via an Ansible role.

Since we assume the virtual machine belongs to an OpenStack tenant and has a floating IP, we are configuring our DNS server such that it listens on any interface.

  • create a working directory:
  mkdir /home/Ansible/PowerDNS
  • download from GitHub:
  cd /home/Ansible/PowerDNS
  ansible-galaxy --roles-path . install PowerDNS.pdns
  • create inventory file in Ansible working directory, with content:
[mydns]
localhost

[mydns:vars]
ansible_user=ansible
  • create manageDNS.yml in Ansible working directory, containing the configuration for your DNS server, read PowerDNS documentation for further information. For example, something like:
- hosts: localhost
  roles:
    - { role: PowerDNS.pdns }
  vars:
    pdns_config:
      daemon: yes
      master: true
      slave: false
      # local-address: # leaving this commented, so DNS will bind to any interface
      disable-axfr: yes
      log-dns-details: on
      loglevel: 3
      slave-cycle-interval: 60
      api: yes
      api-key: superSecretString
      webserver: yes
      # webserver-address: # leaving this commented, so the webserver will listen on any interface
      webserver-password: dnspwd
      # configure next line as needed: add all networks authorized to make queries
      webserver-allow-from: 127.0.0.0/16,10.200.0.0/16,192.168.209.0/24,10.3.0.0/23,193.206.158.0/23
    pdns_backends:
      gmysql:
        host: 127.0.0.1
        port: 3306
        # user/password and PowerDNS database name to create
        user: powerdns
        password: someSafePwdForMyDNS
        dbname: pdns
    pdns_mysql_databases_credentials:
      gmysql:
      # set priv_user and priv_password to your MySQL credentials
        priv_user: root
        priv_password: whateverPwdYouConfiguredForMysqlRoot
        priv_host:
          - "%"
    pdns_install_repo: "\{\{  pdns_auth_powerdns_repo_41  \}\}"
  • run Ansible:
  cd /home/Ansible/PowerDNS
  ansible-playbook -b -v -i inventory.yml manageDNS.yml

PowerDNS-Admin installation and setup

Official documentation for PowerDNS-Admin is available here: lots of useful docs also available in the wiki.

Create the MySQL database as per official instructions for setting the powerdnsadmin database up.

Install PowerDNS-Admin as per official instructions for CentOS 7 or check the relevant page in the wiki for other operating systems.

Once you have PowerDNS-Admin up and running, follow instructions in the wiki to make it a service: I opted for Systemd, other configurations are possible. With respect to the instructions above, I made just coupld of changes:

  • created powerdnsadmin and its group with command:

    useradd --system --user-group powerdnsadmin

  • changed ownership of the PowerDNS-Admin directory:

    chown -R powerdnsadmin.powerdnsadmin /opt/web/powerdns-admin

For reference, I created file config.py by copying config_template.py and modifying:

BIND_ADDRESS = '0.0.0.0'
SQLA_DB_USER = '<choose_your_DB_username>'
SQLA_DB_PASSWORD = '<choose_a_decent_password>'
SQLA_DB_HOST = 'localhost'
PDNS_STATS_URL = 'http://127.0.0.1:8081/'
PDNS_API_KEY = '<whatever_is_set_in_pdns.conf_for_api-key>'