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.
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.