How To

Install PowerDNS on Rocky Linux 10 / AlmaLinux 10 with PowerDNS-Admin

PowerDNS is an open-source authoritative DNS server that serves as a high-performance alternative to BIND. It supports multiple backends including MariaDB, PostgreSQL, and SQLite, making it flexible for different deployment scenarios. PowerDNS-Admin is a web-based management interface that lets you create and manage DNS zones and records through a browser instead of editing config files or running CLI commands. This guide covers a full PowerDNS deployment on Rocky Linux 10 / AlmaLinux 10 with MariaDB as the backend database and PowerDNS-Admin as the web UI.

Original content from computingforgeeks.com - post 64990

We will install PowerDNS from the official repository, configure MariaDB as the storage backend, deploy PowerDNS-Admin behind Nginx as a reverse proxy, and set up firewall rules for DNS (port 53 TCP/UDP) and the web interface (port 8080). SELinux configuration is included so you do not need to disable it.

Prerequisites

  • A server running Rocky Linux 10 or AlmaLinux 10 with root or sudo access
  • At least 2 GB RAM and 2 vCPUs
  • A static IP address assigned to your server
  • Ports 53 (TCP/UDP) and 8080 (TCP) available
  • EPEL repository enabled

Step 1: Update System and Install EPEL Repository

Start by updating your system packages and installing the EPEL repository, which provides additional packages needed for this setup.

sudo dnf -y update
sudo dnf -y install epel-release

Step 2: Install and Configure MariaDB on Rocky Linux 10

PowerDNS uses a database backend to store zone data and DNS records. We will use MariaDB as the backend database for this deployment.

Install MariaDB Server

sudo dnf -y install mariadb-server mariadb

Enable and start the MariaDB service:

sudo systemctl enable --now mariadb

Verify MariaDB is running:

systemctl status mariadb

The output should show the service as active (running):

● mariadb.service - MariaDB database server
     Loaded: loaded (/usr/lib/systemd/system/mariadb.service; enabled; preset: disabled)
     Active: active (running)

Secure MariaDB Installation

Run the security script to set a root password and remove default insecure settings:

sudo mariadb-secure-installation

Answer the prompts – set a strong root password, remove anonymous users, disallow remote root login, and remove the test database.

Create PowerDNS Database and User

Log in to MariaDB and create the database that PowerDNS will use to store DNS records:

sudo mariadb -u root -p

Run the following SQL statements to create the database, user, and grant privileges:

CREATE DATABASE powerdns CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
GRANT ALL ON powerdns.* TO 'pdns'@'localhost' IDENTIFIED BY 'StrongPassword123';
FLUSH PRIVILEGES;
EXIT;

Replace StrongPassword123 with a secure password of your choice. Keep this password – you will need it for the PowerDNS configuration.

Step 3: Install PowerDNS on Rocky Linux 10 / AlmaLinux 10

PowerDNS provides official RPM repositories for Enterprise Linux. We will add the PowerDNS 5.0.x stable repository and install the authoritative server along with the MySQL/MariaDB backend.

Disable systemd-resolved

The systemd-resolved service binds to port 53 by default, which conflicts with PowerDNS. Disable it before installing PowerDNS:

sudo systemctl disable --now systemd-resolved
sudo rm -f /etc/resolv.conf
echo "nameserver 8.8.8.8" | sudo tee /etc/resolv.conf

Add PowerDNS Repository

Install the PowerDNS repository configuration for EL10:

sudo tee /etc/yum.repos.d/pdns.repo > /dev/null <<'EOF'
[pdns-50]
name=PowerDNS Authoritative Server 5.0.x - EL $releasever
baseurl=https://repo.powerdns.com/el/$releasever/$basearch/auth-50
gpgkey=https://repo.powerdns.com/CBC8B383-pub.asc
gpgcheck=1
enabled=1
priority=90
EOF

Install PowerDNS Server and MariaDB Backend

sudo dnf -y install pdns pdns-backend-mysql

Verify the installed version:

pdns_server --version

You should see the PowerDNS version confirming the installation:

PowerDNS Authoritative Server 5.0.x

Step 4: Import PowerDNS Database Schema

PowerDNS ships with a SQL schema file for the MySQL/MariaDB backend. Import it into the database we created earlier:

sudo mariadb -u root -p powerdns < /usr/share/doc/pdns-backend-mysql/schema.mysql.sql

Verify the tables were created successfully:

sudo mariadb -u root -p -e "USE powerdns; SHOW TABLES;"

You should see tables including domains, records, supermasters, comments, domainmetadata, cryptokeys, and tsigkeys:

+--------------------+
| Tables_in_powerdns |
+--------------------+
| comments           |
| cryptokeys         |
| domainmetadata     |
| domains            |
| records            |
| supermasters       |
| tsigkeys           |
+--------------------+

Step 5: Configure PowerDNS with MariaDB Backend

Edit the PowerDNS configuration file to use the MariaDB backend instead of the default BIND backend.

First, back up and clear the default config:

sudo cp /etc/pdns/pdns.conf /etc/pdns/pdns.conf.bak
sudo tee /etc/pdns/pdns.conf > /dev/null <<'EOF'
# PowerDNS Authoritative Server Configuration
# Backend: MariaDB/MySQL

launch=gmysql
gmysql-host=127.0.0.1
gmysql-port=3306
gmysql-dbname=powerdns
gmysql-user=pdns
gmysql-password=StrongPassword123

# API settings (required for PowerDNS-Admin)
api=yes
api-key=YourSecretAPIKey123
webserver=yes
webserver-address=0.0.0.0
webserver-port=8081
webserver-allow-from=127.0.0.1,::1
webserver-password=YourWebServerPassword

# General settings
local-address=0.0.0.0
local-port=53
setgid=pdns
setuid=pdns

# Logging
loglevel=4
log-dns-details=no
log-dns-queries=no

# Security
disable-axfr=no
allow-axfr-ips=127.0.0.0/8
EOF

Replace StrongPassword123 with the actual MariaDB password you set earlier. Also change YourSecretAPIKey123 and YourWebServerPassword to strong unique values - the API key is used by PowerDNS-Admin to communicate with the PowerDNS server.

Remove Default BIND Backend Config

Remove the default BIND backend configuration to avoid conflicts:

sudo rm -f /etc/pdns/pdns.d/bind.conf

Start PowerDNS Service

Enable and start the PowerDNS service:

sudo systemctl enable --now pdns

Check that the service is running:

systemctl status pdns

The service should show active (running). Verify that PowerDNS is listening on port 53:

sudo ss -tulnp | grep pdns

Expected output shows PowerDNS listening on port 53 (DNS) and 8081 (API/webserver):

udp   UNCONN 0      0        0.0.0.0:53        0.0.0.0:*    users:(("pdns_server",pid=xxxx,fd=5))
tcp   LISTEN 0      128      0.0.0.0:53        0.0.0.0:*    users:(("pdns_server",pid=xxxx,fd=7))
tcp   LISTEN 0      128      0.0.0.0:8081      0.0.0.0:*    users:(("pdns_server",pid=xxxx,fd=9))

Step 6: Configure Firewall for PowerDNS

Open the required ports in firewalld for DNS traffic and the PowerDNS-Admin web interface:

sudo firewall-cmd --permanent --add-service=dns
sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --reload

This opens port 53 TCP/UDP (DNS service) and port 8080 TCP (for the PowerDNS-Admin web UI behind Nginx). Verify the firewall rules:

sudo firewall-cmd --list-all

You should see dns and 8080/tcp listed under services and ports respectively.

Step 7: Configure SELinux for PowerDNS

Rather than disabling SELinux, configure it to allow PowerDNS to operate correctly. Allow PowerDNS to connect to the database and bind to the required ports:

sudo setsebool -P httpd_can_network_connect 1
sudo setsebool -P httpd_can_network_connect_db 1

If PowerDNS fails to start with SELinux enabled, check the audit log and generate a custom policy:

sudo dnf -y install policycoreutils-python-utils
sudo ausearch -c 'pdns_server' --raw | audit2allow -M pdns_custom
sudo semodule -i pdns_custom.pp

Verify SELinux is enforcing:

getenforce

This should return Enforcing.

Step 8: Install PowerDNS-Admin Web Interface

PowerDNS-Admin is a web-based management tool for PowerDNS that provides a GUI for managing zones, records, and server settings. We will install it using Python virtual environment.

Install Required Dependencies

sudo dnf -y install python3 python3-devel python3-pip gcc mariadb-devel openldap-devel xmlsec1-devel xmlsec1-openssl-devel libtool-ltdl-devel libxml2-devel libxslt-devel git cargo pkg-config openssl-devel

Create PowerDNS-Admin Database

Create a separate database for PowerDNS-Admin to store its own configuration and user data:

sudo mariadb -u root -p

Run the following SQL commands:

CREATE DATABASE powerdns_admin CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
GRANT ALL ON powerdns_admin.* TO 'pdnsadmin'@'localhost' IDENTIFIED BY 'AdminDBPassword123';
FLUSH PRIVILEGES;
EXIT;

Replace AdminDBPassword123 with a strong password.

Clone and Set Up PowerDNS-Admin

sudo git clone https://github.com/PowerDNS-Admin/PowerDNS-Admin.git /opt/powerdns-admin

Create a Python virtual environment and install the required packages:

cd /opt/powerdns-admin
sudo python3 -m venv venv
sudo -s
source /opt/powerdns-admin/venv/bin/activate
pip install --upgrade pip setuptools wheel
pip install -r requirements.txt

Configure PowerDNS-Admin

Copy the example configuration and edit it:

cp /opt/powerdns-admin/configs/development.py /opt/powerdns-admin/configs/production.py
vi /opt/powerdns-admin/configs/production.py

Update the following settings in the configuration file:

import os
basedir = os.path.abspath(os.path.dirname(__file__))

# Database connection
SQLALCHEMY_DATABASE_URI = 'mysql://pdnsadmin:AdminDBPassword123@localhost/powerdns_admin'
SQLALCHEMY_TRACK_MODIFICATIONS = False

# Secret key - generate a random string
SECRET_KEY = 'YourRandomSecretKeyHere'

# PowerDNS API connection
PDNS_STATS_URL = 'http://127.0.0.1:8081'
PDNS_API_KEY = 'YourSecretAPIKey123'
PDNS_VERSION = '5.0.0'

# Session settings
SESSION_TYPE = 'sqlalchemy'

Make sure the PDNS_API_KEY matches the api-key value you set in /etc/pdns/pdns.conf earlier.

Initialize the Database and Build Assets

Set the Flask configuration environment variable and initialize the database:

export FLASK_CONF=production
export FLASK_APP=/opt/powerdns-admin/powerdnsadmin/__init__.py
flask db upgrade
yarn install --pure-lockfile
flask assets build

Install Node.js and Yarn if not already present:

sudo dnf -y install nodejs npm
sudo npm install -g yarn

Then run the build commands again if needed:

cd /opt/powerdns-admin
source venv/bin/activate
export FLASK_CONF=production
export FLASK_APP=/opt/powerdns-admin/powerdnsadmin/__init__.py
yarn install --pure-lockfile
flask assets build

Create Systemd Service for PowerDNS-Admin

Create a systemd service file so PowerDNS-Admin starts automatically on boot:

sudo vi /etc/systemd/system/powerdns-admin.service

Add the following content:

[Unit]
Description=PowerDNS-Admin
Requires=mariadb.service
After=mariadb.service

[Service]
Type=simple
User=root
Group=root
Environment=FLASK_CONF=production
Environment=FLASK_APP=/opt/powerdns-admin/powerdnsadmin/__init__.py
WorkingDirectory=/opt/powerdns-admin
ExecStart=/opt/powerdns-admin/venv/bin/gunicorn --workers 4 --bind 127.0.0.1:9191 "powerdnsadmin:create_app()"
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

Install gunicorn in the virtual environment, then enable and start the service:

source /opt/powerdns-admin/venv/bin/activate
pip install gunicorn
deactivate
sudo systemctl daemon-reload
sudo systemctl enable --now powerdns-admin

Verify the service is running:

systemctl status powerdns-admin

The service should show active (running) with gunicorn workers listening on port 9191.

Step 9: Configure Nginx Reverse Proxy for PowerDNS-Admin

Set up Nginx as a reverse proxy to serve the PowerDNS-Admin web interface on port 8080.

Install Nginx

sudo dnf -y install nginx

Create Nginx Virtual Host

sudo vi /etc/nginx/conf.d/powerdns-admin.conf

Add the following Nginx configuration:

server {
    listen 8080;
    server_name _;

    index index.html index.htm;
    root /opt/powerdns-admin/powerdnsadmin;

    access_log /var/log/nginx/powerdns-admin-access.log;
    error_log /var/log/nginx/powerdns-admin-error.log;

    location / {
        proxy_pass http://127.0.0.1:9191;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /static/ {
        alias /opt/powerdns-admin/powerdnsadmin/static/;
        expires 30d;
    }
}

Test the Nginx configuration and start the service:

sudo nginx -t
sudo systemctl enable --now nginx

Verify Nginx is running and listening on port 8080:

sudo ss -tulnp | grep ':8080'

You should see Nginx listening on port 8080:

tcp   LISTEN 0      511      0.0.0.0:8080      0.0.0.0:*    users:(("nginx",pid=xxxx,fd=6))

Step 10: Access PowerDNS-Admin and Create Initial Account

Open your browser and navigate to http://your-server-ip:8080. The first user to register becomes the administrator. Create your admin account by clicking the registration link on the login page.

After logging in, go to Settings and configure the PowerDNS API connection:

  • PowerDNS API URL: http://127.0.0.1:8081
  • PowerDNS API Key: The API key you set in pdns.conf
  • PowerDNS Version: 5.0.x

Step 11: Create DNS Zones and Add Records

You can create zones and add records either through the PowerDNS-Admin web UI or using the pdnsutil command-line tool.

Create a Zone Using pdnsutil

Create a new DNS zone from the command line:

sudo pdnsutil create-zone example.com ns1.example.com

This creates the zone example.com with ns1.example.com as the primary nameserver. Verify the zone was created:

sudo pdnsutil list-zone example.com

The output shows the default SOA and NS records for the zone:

example.com	3600	IN	NS	ns1.example.com.
example.com	3600	IN	SOA	ns1.example.com. hostmaster.example.com. 1 10800 3600 604800 3600

Add DNS Records

Add an A record for the zone:

sudo pdnsutil add-record example.com @ A 3600 192.168.1.10
sudo pdnsutil add-record example.com www A 3600 192.168.1.10
sudo pdnsutil add-record example.com mail A 3600 192.168.1.11
sudo pdnsutil add-record example.com @ MX 3600 "10 mail.example.com."

Add an NS record for a secondary nameserver:

sudo pdnsutil add-record example.com @ NS 3600 ns2.example.com.
sudo pdnsutil add-record example.com ns1 A 3600 192.168.1.10
sudo pdnsutil add-record example.com ns2 A 3600 192.168.1.12

List all records in the zone to verify:

sudo pdnsutil list-zone example.com

You can also create zones and add records through the PowerDNS-Admin web interface by navigating to Dashboard and clicking "New Domain".

Step 12: Verify DNS Resolution with dig

Test that PowerDNS is resolving queries correctly using the dig command. Install bind-utils if not already present:

sudo dnf -y install bind-utils

Query the local PowerDNS server for the A record:

dig @127.0.0.1 example.com A

The response should include the A record you created with a status of NOERROR:

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 12345
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; ANSWER SECTION:
example.com.		3600	IN	A	192.168.1.10

Test the MX record:

dig @127.0.0.1 example.com MX

The response should show the MX record pointing to mail.example.com:

;; ANSWER SECTION:
example.com.		3600	IN	MX	10 mail.example.com.

Test the NS records:

dig @127.0.0.1 example.com NS

Both nameservers should appear in the response:

;; ANSWER SECTION:
example.com.		3600	IN	NS	ns1.example.com.
example.com.		3600	IN	NS	ns2.example.com.

Conclusion

You have a fully working PowerDNS authoritative server on Rocky Linux 10 / AlmaLinux 10 with MariaDB as the backend and PowerDNS-Admin providing a web management interface through Nginx reverse proxy. DNS zones and records can be managed from the web UI or the command line using pdnsutil.

For production deployments, consider enabling DNSSEC with pdnsutil secure-zone, setting up master-slave replication for high availability, and placing the PowerDNS-Admin interface behind SSL using Let's Encrypt. Monitor DNS query performance with the built-in PowerDNS statistics API at http://127.0.0.1:8081/api/v1/servers/localhost/statistics.

Related Articles

CentOS Configure Dropbox Client on Rocky Linux 10 | CentOS Stream 10 Containers Deploy k0s Kubernetes on Rocky Linux 9 using k0sctl CentOS Install Ruby 3 on RHEL 8|CentOS 8|Rocky Linux 8 AlmaLinux Deploy 3-Node RabbitMQ Cluster on Rocky Linux 10 / AlmaLinux 10

Press ESC to close