This is an old revision of the document!
Table of Contents
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). 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 = "xW4dC7vV3iJ2wT8dY3eY7fF6uC6lD4nF" SECRET_KEY = "pC4uT1nA4pF4aQ1pM1tH9tR5pE5yS6hA" 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 [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