User Tools

Site Tools


os:linux:powerdns_apache_postgresql_debian

This is an old revision of the document!


PowerDNS via Apache2 with PostgreSQL on Debian and PowerDNS-Admin

How to setup a PowerDNS Authoritative Server with PowerDNS-Admin as management web interface.

This guide expects an existing PostgreSQL 13 (should work on older versions) and Apach2 installation on a Debian 10 server.

Used software:

  • Debian 10.6
  • PowerDNS Authoritative Server 4.3.1
  • PostgreSQL 13
  • Python 3.7.3
  • uWSGI 2.0.19.1
  • Apache 2.4.46

Install PowerDNS

Configure APT Repository

Create a file with the repositories of PowerDNS (see https://repo.powerdns.com/).

vim /etc/apt/sources.list.d/pdns.list
pdns.list
deb http://repo.powerdns.com/debian buster-rec-43 main
deb http://repo.powerdns.com/debian buster-auth-43 main
deb http://repo.powerdns.com/debian buster-dnsdist-15 main

Add the key for this repositories.

curl https://repo.powerdns.com/FD380FBB-pub.asc | sudo apt-key add -

Install PowerDNS Authoritative Server with PostgreSQL backend.

apt install pdns-backend-pgsql

Prepare PostgreSQL Database

Open psql.

su - postgres
psql

Create the user u_powerdns and the database db_powerdns. Change the example password with your own generated one (eg. https://strongpasswordgenerator.com/).

CREATE USER u_powerdns WITH PASSWORD 'iC0iB9kQ5hR4oG5uW2nD2nV0gK6vN2eSoM2eI8kT0gA9rF2pS3wW7mO4sJ4aT5tN';
CREATE DATABASE db_powerdns OWNER u_powerdns;
\q

Edit pg_hba.conf to configure the connections for the new database.

vim /etc/postgresql/13/main/pg_hba.conf

Add following line to provide access to the database db_powerdns via unix socket.

pg_hba.conf
local   db_powerdns         u_powerdns                      peer

Reload the PostgreSQL cluster.

pg_ctlcluster 13 main reload

Import Schema

Get the database schema for the related PowerDNS Authoritative Server version from GitHub and import it.

su - postgres
wget https://raw.githubusercontent.com/PowerDNS/pdns/rel/auth-4.3.x/modules/gpgsqlbackend/schema.pgsql.sql
psql -U u_powerdns -f schema.pgsql.sql db_powerdns

Configure PowerDNS Authoritative Server

Edit the PowerDNS configuration file (you may want to create a backup before).

vim /etc/powerdns/pdns.conf

Replace the database password with the one you generated before. Generate your own API key (used for PowerDNS-Admin). Change the other settings according to your needs.

pdns.conf
# https://doc.powerdns.com/authoritative/settings.html
#webserver-address=127.0.0.1,::1
 
setuid=pdns
setgid=pdns
 
# https://doc.powerdns.com/authoritative/backends/generic-postgresql.html
launch=gpgsql
gpgsql-host=/var/run/postgresql
#gpgsql-port=
gpgsql-dbname=db_powerdns
gpgsql-user=u_powerdns
gpgsql-password=iC0iB9kQ5hR4oG5uW2nD2nV0gK6vN2eSoM2eI8kT0gA9rF2pS3wW7mO4sJ4aT5tN
gpgsql-dnssec=yes
 
loglevel=4
master=yes
slave=no
webserver=yes
api=yes
api-key=aF3kD4eJ0hB1uI1jV8vR2yC0eK8lP9mO
daemon=no
guardian=no
default-publish-cdnskey=1
default-publish-cds=2,4
webserver-port=8081
webserver-allow-from=127.0.0.1,::1
#allow-axfr-ips=0.0.0.0/0,::/0
#allow-notify-from=0.0.0.0/0,::/0
enable-lua-records=1
version-string=anonymous
default-soa-edit=INCEPTION-INCREMENT

Install PowerDNS-Admin

Prepare PostgreSQL Database

Open psql.

su - postgres
psql

Create the user u_powerdns and the database db_powerdns. Change the example password with your own generated one (eg. https://strongpasswordgenerator.com/).

CREATE USER u_powerdnsadmin WITH PASSWORD 'hW2bD6rM7vK0vB8fN7dJ8iI1lH3eJ5eQiD7qE7kH6gT1rE9vV2gT2hH3vL2lD7jW';
CREATE DATABASE db_powerdnsadmin OWNER u_powerdnsadmin;
\q

Edit pg_hba.conf to configure the connections for the new database.

vim /etc/postgresql/13/main/pg_hba.conf

Add following line to provide access to the database db_powerdns via unix socket.

pg_hba.conf
local   db_powerdnsadmin    u_powerdnsadmin                 peer

Reload the PostgreSQL cluster.

pg_ctlcluster 13 main reload

Install NodeJS

Install NodeJS according to https://github.com/nodesource/distributions/blob/master/README.md.

curl -sL https://deb.nodesource.com/setup_14.x | bash -
apt install -y nodejs

Install Yarn

Install Yarn according to https://classic.yarnpkg.com/en/docs/install/#debian-stable.

curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
apt update
apt install yarn

Setup PowerDNS-Admin from GitHub

Create the local directories and clonde the GitHub repository of PowerDNS-Admin.

mkdir -p /opt/python/powerdns-admin/
git clone https://github.com/ngoduykhanh/PowerDNS-Admin.git /opt/python/powerdns-admin/app
cd /opt/python/powerdns-admin/app

Install the requirements.

apt install libmariadb-dev build-essential python3-dev libldap2-dev libsasl2-dev pkg-config libxmlsec1-dev

This requirements are expected by this python libraries:

  • python-ldap: build-essential python3-dev libldap2-dev libsasl2-dev slapd ldap-utils tox lcov valgrind
  • mysqlclient: libmariadbclient-dev:

Create the config file /opt/python/powerdns-admin/app/configs/config.py.

vim /opt/python/powerdns-admin/app/configs/config.py

Generate new values for the variables SALT and SECRET_KEY (32 chars).

Generate a new salt:

# /opt/python/powerdns-admin/venv/bin/python3 -c 'import bcrypt; print(bcrypt.gensalt().decode("utf-8"))'
$2b$12$E0Dn1LmXonAUiCP8sM0htu

Generate a new secret key:

# tr -dc _A-Z-a-z-0-9 </dev/urandom| head -c${1:-32}; echo;
iz7g4zpfvbnK_eb0lWZeFEuXn5UV93Yz

This config.py is based on /opt/python/powerdns-admin/app/powerdnsadmin/default_config.py. Details about Unix domain connections of SQLAlchemy you can find in their documentation: Documentation

config.py
import os
basedir = os.path.abspath(os.path.abspath(os.path.dirname(__file__)))
 
### BASIC APP CONFIG
SALT = "$2b$12$E0Dn1LmXonAUiCP8sM0htu"
SECRET_KEY = "iz7g4zpfvbnK_eb0lWZeFEuXn5UV93Yz"
BIND_ADDRESS = "0.0.0.0"
PORT = 9191
HSTS_ENABLED = False
OFFLINE_MODE = False
 
### DATABASE CONFIG
SQLA_DB_DRIVER = "postgres" # mysql, postgres
SQLA_DB_USER = "u_powerdnsadmin"
SQLA_DB_PASSWORD = ''
#SQLA_DB_HOST = '127.0.0.1'
SQLA_DB_HOST = ""
SQLA_DB_NAME = "db_powerdnsadmin"
SQLALCHEMY_TRACK_MODIFICATIONS = True
 
### DATABASE - MySQL
SQLALCHEMY_DATABASE_URI = f"{SQLA_DB_DRIVER}://{SQLA_DB_USER}:{SQLA_DB_PASSWORD}@{SQLA_DB_HOST}/{SQLA_DB_NAME}"
 
### DATABASE - SQLite
# SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'pdns.db')
 
# SAML Authnetication
SAML_ENABLED = False
SAML_ASSERTION_ENCRYPTED = True

Create and activate a venv for PowerDNS-Admin.

python3 -m venv /opt/python/powerdns-admin/venv
. /opt/python/powerdns-admin/venv/bin/activate

VENV Change to the required directory for the next steps.

cd /opt/python/powerdns-admin/app/

VENV Install all the requirements from pip.

pip install wheel
pip install -r /opt/python/powerdns-admin/app/requirements.txt
pip install psycopg2-binary

VENV Define the flask variables.

export FLASK_CONF="/opt/python/powerdns-admin/app/configs/config.py"
export FLASK_APP="/opt/python/powerdns-admin/app/powerdnsadmin/__init__.py"

VENV Initialize the database.

flask db upgrade

VENV Install the JavaScript components.

yarn install --pure-lockfile

VENV Build webassets (JavaScript and CSS files).

flask assets build

VENV Quit the venv.

deactivate

Set the permissions.

chown -R www-data:www-data /opt/python/powerdns-admin/

Setup uWSGI

Create and set the permissions for the directory which uWSGI will use for the pid file and the unix sockets.

Create the uWSGI configuration directory.

mkdir /etc/uwsgi/

Create the uWSGI configuration file for the PowerDNS-Admin service.

vim /etc/uwsgi/powerdns-admin.ini

The number of processes shouldn't be higher than the numbers of CPUs in the system.

powerdns-admin.ini
[uwsgi]
strict = true
vacuum = true
single-interpreter = true
die-on-term = true
need-app = true
uid = www-data
gid = www-data
uwsgi-socket = /run/uwsgi_%n/service.sock
wsgi-file = /opt/python/%n/app/wsgi.py
processes = 1
threads = 4
master = true
max-requests = 1000
auto-procname = true
procname-prefix-spaced = %n
venv = /opt/python/%n/venv/
buffer-size = 65535
;disable-logging = true
;log-4xx = true
;log-5xx = true

Create the start file for the application.

vim /opt/python/powerdns-admin/app/wsgi.py
wsgi.py
#!/usr/bin/env python3
import sys
 
APP_PATH = "/opt/python/powerdns-admin/app/"
CONFIG_PATH = f"{APP_PATH}configs/config.py"
 
sys.path.insert(0, APP_PATH)
 
from powerdnsadmin import create_app
application = create_app(CONFIG_PATH)

Create a service file for systemd.

vim /etc/systemd/system/uwsgi@powerdns-admin.service
uwsgi@powerdns-admin.service
[Unit]
Description=uWSGI service unit %i
After=syslog.target
 
[Service]
User=www-data
Group=www-data
RuntimeDirectory=uwsgi_%i
PIDFile=/run/uwsgi_%i/service.pid
RemainAfterExit=yes
ExecStart=/usr/local/bin/uwsgi --ini /etc/uwsgi/%i.ini
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/bin/kill -INT $MAINPID
Restart=always
KillSignal=SIGQUIT
Type=notify
NotifyAccess=all
SuccessExitStatus=15 17 29 30
NoNewPrivileges=yes
LimitNOFILE=65536
 
 
[Install]
WantedBy=multi-user.target

Let systemd re-read the service files.

systemctl daemon-reload

Install uwsgi globally on the system (not in a venv).

python3 -m pip install uwsgi

Start PowerDNS-Admin and let it start on the system startup.

systemctl start uwsgi@powerdns-admin.service
systemctl enable uwsgi@powerdns-admin.service

Enable the uWSGI extension for mod_proxy.

a2enmod proxy_uwsgi

Setup a VHost configuration. Change the name, certificate and the Content-Security-Policy according to your needs.

/etc/apache2/sites-available/pdnsadmin.example.com.conf
pdnsadmin.example.com.conf
<VirtualHost *:80>
    ServerName pdnsadmin.example.com
    ServerAdmin hostmaster@example.com
 
    Redirect / https://pdnsadmin.example.com/
 
    ErrorLog ${APACHE_LOG_DIR}/pdnsadmin.example.com-error.log
    LogLevel warn
    CustomLog ${APACHE_LOG_DIR}/pdnsadmin.example.com-access.log combined
</VirtualHost>
 
<IfModule mod_ssl.c>
<VirtualHost *:443>
    ServerName pdnsadmin.example.com
    ServerAdmin hostmaster@example.com
 
    DocumentRoot /opt/python/powerdns-admin/app/powerdnsadmin/
 
    <Directory "/opt/python/powerdns-admin/app/powerdnsadmin/static">
        AllowOverride None
        Require all granted
    </Directory>
 
    ProxyPass "/static/" "!"
    ProxyPass "/favicon.ico" "!"
    ProxyPass "/.well-known/" "!"
    ProxyPass "/" "unix:/run/uwsgi_powerdns-admin/service.sock|uwsgi://localhost/powerdns-admin/"
 
    ErrorLog ${APACHE_LOG_DIR}/pdnsadmin.example.com-error.log
    LogLevel warn
    CustomLog ${APACHE_LOG_DIR}/pdnsadmin.example.com-access.log combined
 
    SSLEngine on
    SSLCertificateFile    /etc/dehydrated/certs/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/dehydrated/certs/example.com/privkey.pem
 
    <IfModule mod_headers.c>
        # enable HSTS
        Header always set Strict-Transport-Security "max-age=15768000"
        # allow frames, needed for settings page
        Header always set X-Frame-Options SAMEORIGIN
        # Content Security Policy (https://content-security-policy.com/)
        Header set Content-Security-Policy: "default-src 'self' *.example.com 'unsafe-inline' 'unsafe-eval'"
    </IfModule>
</VirtualHost>
</IfModule>

Enable the new VHost.

a2ensite pdnsadmin.example.com

PowerDNS-Admin Configuration via Browser

  • Open a browser and access this VHost (eg. https://pdnsadmin.example.com/)
  • Create an account
  • Configure the PDNS API settings based on pdns.conf
    • Settings, PDNS
    • PDNS API URL: http://127.0.0.1:8081/
    • PDNS API KEY: aF3kD4eJ0hB1uI1jV8vR2yC0eK8lP9mO
    • PDNS VERSION: 4.3.1

Appendix

If you want to migrate from Bind to PowerDNS, you can find some notes here: Bind to PowerDNS

os/linux/powerdns_apache_postgresql_debian.1612703735.txt.gz · Last modified: 2021-02-07 14:15 by Manuel Frei