How to Install PowerDNS on Ubuntu 18.04

PowerDNS is a free and open source DNS server written in C++ language that can be used to host domains using DNSSEC. It runs on most unix-based operating systems and uses databases like MariaDB, MySQL, PostgreSQL and SQLite to store its DNS entries. PowerDNS uses Packet Cache and Query Cache to cache backend queries. PowerDNS comes with a built-in web based tool: PowerDNS-Admin, which can be used to manage PowerDNS through web interface.

In this tutorial, we will explain how to install PowerDNS on an Ubuntu 18.04 cloud server.

Requirements

  • A vps cloud server running on Ubuntu 18.04.
  • A root password setup on your server.

Getting Started

First, it is recommended to update your server with the latest version. You can do it with the following command:
# apt-get update -y
# apt-get upgrade -y

Once your system is updated, restart it to apply all the changes.

Install and Configure MariaDB

First, you will need to install MariaDB database in your server. You can install it by running the following command:
# apt-get install mariadb-server mariadb-client -y
Once the installation has been completed, you will need to create database and user for PowerDNS.

First, log in to MariaDB shell with the following command:
# mysql -u root -p

Provide your root password when prompt, then create a database and user for PowerDNS with the following command:
MariaDB [(none)]>CREATE DATABASE powerdns;
MariaDB [(none)]>GRANT ALL ON powerdns.* TO 'powerdns'@'localhost' IDENTIFIED BY 'password';

Next, flush the privileges with the following command:
MariaDB [(none)]>FLUSH PRIVILEGES;
Next, change the database to PowerDNS and create required tables with the following command:

MariaDB [(none)]>USE powerdns;

MariaDB [powerdns]>CREATE TABLE domains ( id INT AUTO_INCREMENT, name VARCHAR(255) NOT NULL, master VARCHAR(128) DEFAULT NULL, last_check INT DEFAULT NULL, type VARCHAR(6) NOT NULL, notified_serial INT UNSIGNED DEFAULT NULL, account VARCHAR(40) CHARACTER SET ‘utf8’ DEFAULT NULL, PRIMARY KEY (id) ) Engine=InnoDB CHARACTER SET ‘latin1’;

MariaDB [powerdns]>CREATE UNIQUE INDEX name_index ON domains(name);

MariaDB [powerdns]>CREATE TABLE records ( id BIGINT AUTO_INCREMENT, domain_id INT DEFAULT NULL, name VARCHAR(255) DEFAULT NULL, type VARCHAR(10) DEFAULT NULL, content VARCHAR(64000) DEFAULT NULL, ttl INT DEFAULT NULL, prio INT DEFAULT NULL, change_date INT DEFAULT NULL, disabled TINYINT(1) DEFAULT 0, ordername VARCHAR(255) BINARY DEFAULT NULL, auth TINYINT(1) DEFAULT 1, PRIMARY KEY (id) ) Engine=InnoDB CHARACTER SET ‘latin1’;

MariaDB [powerdns]>CREATE INDEX nametype_index ON records(name,type);
MariaDB [powerdns]>CREATE INDEX domain_id ON records(domain_id);
MariaDB [powerdns]>CREATE INDEX ordername ON records (ordername);

MariaDB [powerdns]>CREATE TABLE supermasters ( ip VARCHAR(64) NOT NULL, nameserver VARCHAR(255) NOT NULL, account VARCHAR(40) CHARACTER SET ‘utf8’ NOT NULL, PRIMARY KEY (ip, nameserver) ) Engine=InnoDB CHARACTER SET ‘latin1’;
3 MariaDB [powerdns]>CREATE TABLE comments ( id INT AUTO_INCREMENT, domain_id INT NOT NULL, name VARCHAR(255) NOT NULL, type VARCHAR(10) NOT NULL, modified_at INT NOT NULL, account VARCHAR(40) CHARACTER SET ‘utf8’ DEFAULT NULL, comment TEXT CHARACTER SET ‘utf8’ NOT NULL, PRIMARY KEY (id) ) Engine=InnoDB CHARACTER SET ‘latin1’;

MariaDB [powerdns]>CREATE INDEX comments_name_type_idx ON comments (name, type);
MariaDB [powerdns]>CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);

MariaDB [powerdns]>CREATE TABLE domainmetadata ( id INT AUTO_INCREMENT, domain_id INT NOT NULL, kind VARCHAR(32), content TEXT, PRIMARY KEY (id) ) Engine=InnoDB CHARACTER SET ‘latin1’;

MariaDB [powerdns]>CREATE INDEX domainmetadata_idx ON domainmetadata (domain_id, kind);

MariaDB [powerdns]>CREATE TABLE cryptokeys ( id INT AUTO_INCREMENT, domain_id INT NOT NULL, flags INT NOT NULL, active BOOL, content TEXT, PRIMARY KEY(id)) Engine=InnoDB CHARACTER SET ‘latin1’;

MariaDB [powerdns]>CREATE INDEX domainidindex ON cryptokeys(domain_id);

MariaDB [powerdns]>CREATE TABLE tsigkeys ( id INT AUTO_INCREMENT, name VARCHAR(255), algorithm VARCHAR(50), secret VARCHAR(255), PRIMARY KEY (id)) Engine=InnoDB CHARACTER SET ‘latin1’;

MariaDB [powerdns]>CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm);

You can also check the created tables with the following command:
MariaDB [powerdns]> show tables;
+--------------------+
| Tables_in_powerdns |
+--------------------+
| comments           |
| cryptokeys         |
| domainmetadata     |
| domains            |
| records            |
| supermasters       |
| tsigkeys           |
+--------------------+
7 rows in set (0.00 sec)

Install PowerDNS

First, you will need to disable systemd-resolve in order to PowerDNS work properly.

You can do it with the following command:
# systemctl disable systemd-resolved
# systemctl stop systemd-resolved

Next, remove the default resolv.conf file and create new one with the following command:
# rm /etc/resolv.conf
# echo "nameserver 8.8.8.8" > /etc/resolv.conf

Now, install PowerDNS with the following command:
# apt-get install pdns-server pdns-backend-mysql virtualenv -y
During the installation, you will be asked whether to configure the PowerDNS database with dbconfig-common. Select No and press Enter to continue the installation.

Next, you will need to configure PowerDNS to use MySQL. You can do it by editing PowerDNS configuration file:
# nano /etc/powerdns/pdns.d/pdns.local.gmysql.conf

Make the following changes:

launch+=gmysql
gmysql-host=localhost
gmysql-port=3306
gmysql-dbname=powerdns
gmysql-user=powerdns
gmysql-password=password
gmysql-dnssec=yes

Save and close the file. Then, restart PowerDNS service to apply the changes:
# systemctl restart pdns
You can also check the status of PowerDNS with the following command:
# systemctl status pdns
You should see the following output:

    • pdns.service – PowerDNS Authoritative Server

 

Loaded: loaded (/lib/systemd/system/pdns.service; enabled; vendor preset: enabled) Active: active (running) since Mon 2019-06-24 15:29:08 UTC; 5s ago Docs: man:pdns_server(1) man:pdns_control(1) https://doc.powerdns.com Main PID: 8915 (pdns_server) Tasks: 8 (limit: 1718) CGroup: /system.slice/pdns.service └─8915 /usr/sbin/pdns_server –guardian=no –daemon=no –disable-syslog –log-timestamp=no –write-pid=no Jun 24 15:29:08 ubuntu1804 pdns_server[8915]: TCPv6 server bound to [::]:53 Jun 24 15:29:08 ubuntu1804 pdns_server[8915]: PowerDNS Authoritative Server 4.1.1 (C) 2001-2017 PowerDNS.COM BV Jun 24 15:29:08 ubuntu1804 pdns_server[8915]: Using 64-bits mode. Built using gcc 7.3.0. Jun 24 15:29:08 ubuntu1804 pdns_server[8915]: PowerDNS comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistr Jun 24 15:29:08 ubuntu1804 pdns_server[8915]: Creating backend connection for TCP Jun 24 15:29:08 ubuntu1804 pdns_server[8915]: [bindbackend] Parsing 0 domain(s), will report when done Jun 24 15:29:08 ubuntu1804 pdns_server[8915]: [bindbackend] Done parsing domains, 0 rejected, 0 new, 0 removed Jun 24 15:29:08 ubuntu1804 systemd[1]: Started PowerDNS Authoritative Server. Jun 24 15:29:08 ubuntu1804 pdns_server[8915]: About to create 3 backend threads for UDP Jun 24 15:29:08 ubuntu1804 pdns_server[8915]: Done launching threads, ready to distribute questions

Install PowerDNS-Admin

Next, you will need to install PowerDNS-Admin web interface to your server. You can manage domain, user, local DB, LDAP, PowerDNS service and much more with PowerDNS-Admin.

First, you will need to install some packages required for PowerDNS-Admin to your server. You can install all of them with the following command:
# apt-get install python3-dev libmysqlclient-dev python-mysqldb libsasl2-dev libffi-dev libldap2-dev libssl-dev libxml2-dev libxslt1-dev libxmlsec1-dev pkg-config -y

Next, you will also need to install yarn to your server.

First, download and add the GPG key with the following command:
# curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -

Next, add the yarn repository with the following command:
# echo "deb https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list

Next, update the repository and install yarn with the following command:
# apt-get update -y
# apt-get install  yarn -y

Next, download the latest version of PowerDNS-Admin from the Git repository:
# git clone https://github.com/ngoduykhanh/PowerDNS-Admin.git /opt/web/powerdns-admin

Next, create the virtual environment for PowerDNS-Admin with the following command:
# cd /opt/web/powerdns-admin
# virtualenv -p python3 flask

Next, activate the python3 environment and install all the required packages with the following command:
# . ./flask/bin/activate
# pip install -r requirements.txt

Next, you will need to rename config_template.py file and define your database in this file:
# mv config_template.py config.py
# nano config.py

Make the following changes:

SQLA_DB_USER = 'powerdns'
SQLA_DB_PASSWORD = 'password'
SQLA_DB_HOST = 'localhost'
SQLA_DB_NAME = 'powerdns'
#MySQL
SQLALCHEMY_DATABASE_URI = 'mysql://'+SQLA_DB_USER+':'+SQLA_DB_PASSWORD+'@'+SQLA_DB_HOST+'/'+SQLA_DB_NAME
SQLite
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'pdns.db')

Save and close the file. Then, create the database schema file:
export FLASK_APP=app/__init__.py
flask db upgrade
flask db migrate -m "Init DB"

Next, generate the asset files using the yarn command as shown below:
# yarn install --pure-lockfile
# flask assets build

You should see the following output:

Building bundle: generated/login.js[2019-06-24 16:27:54,218] [INFO] | Building bundle: generated/login.js
Building bundle: generated/validation.js
[2019-06-24 16:27:54,848] [INFO] | Building bundle: generated/validation.js
Building bundle: generated/login.css
[2019-06-24 16:27:54,859] [INFO] | Building bundle: generated/login.css
Building bundle: generated/main.js
[2019-06-24 16:29:31,467] [INFO] | Building bundle: generated/main.js
Building bundle: generated/main.css
[2019-06-24 16:29:34,217] [INFO] | Building bundle: generated/main.css

Next, you can check your PowerDNS-Admin with the following command:
# ./run.py
* Serving Flask app "app" (lazy loading)
* Environment: production

WARNING: Do not use the development server in a production environment.Use a production WSGI server instead.

# * Debug mode: on
# [2019-06-24 16:49:06,065] [INFO] |  * Running on http://127.0.0.1:9191/ (Press CTRL+C to quit)
# [2019-06-24 16:49:06,068] [INFO] |  * Restarting with stat
# [2019-06-24 16:49:19,104] [WARNING] |  * Debugger is active!
# [2019-06-24 16:49:19,107] [INFO] |  * Debugger PIN: 193-133-562

Install and Configure Nginx

Next, you will need to install Nginx to access PowerDNS-Admin from web browser.

First, install Nginx with the following command:
# apt-get install nginx -y

Next, you will need to create an Nginx virtual host file for PowerDNS-Admin. You can do it with the following command:
# nano /etc/nginx/conf.d/powerdns-admin.conf

Add the following lines:

server {
 listen *:80;
 server_name               example.com;

 index                     index.html index.htm index.php;
 root                      /opt/web/powerdns-admin;
 access_log                /var/log/nginx/powerdns.access.log combined;
 error_log                 /var/log/nginx/powerdns.error.log;
 client_max_body_size              10m;
 client_body_buffer_size           128k;
 proxy_redirect                    off;
 proxy_connect_timeout             90;
 proxy_send_timeout                90;
 proxy_read_timeout                90;
 proxy_buffers                     32 4k;
 proxy_buffer_size                 8k;
 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_headers_hash_bucket_size    64;

 location ~ ^/static/  {
 include  /etc/nginx/mime.types;
 root /opt/web/powerdns-admin/app;

 location ~*  \.(jpg|jpeg|png|gif)$ {
 expires 365d;
}

 location ~* ^.+.(css|js)$ {
 expires 7d;
 }
}

 location / {
 proxy_pass            http://unix:/opt/web/powerdns-admin/powerdns-admin.sock;
 proxy_read_timeout    120;
 proxy_connect_timeout 120;
 proxy_redirect        off;
 }
}

Save and close the file, when you are finished. Then, restart Nginx service to apply all the changes:
# systemctl restart nginx

Create Systemd Service file for PowerDNS-Admin

Next, you will need to create a systemd service file for PowerDNS-Admin. So, you can start, stop, and manage PowerDNS-Admin service. You can do it with the following command:
# nano /etc/systemd/system/powerdns.service
Add the following lines:

[Unit]
Description=PowerDNS-Admin
After=network.target

[Service]
User=root
Group=root
WorkingDirectory=/opt/web/powerdns-admin
ExecStart=/opt/web/powerdns-admin/flask/bin/gunicorn --workers 2 --bind unix:/opt/web/powerdns-admin/powerdns-admin.sock app:app

[Install]
WantedBy=multi-user.target

Save and close the file, when you are finished. Then, start PowerDNS-Admin service and enable it to start on boot  with the following command:
# systemctl daemon-reload
# systemctl start powerdns
# systemctl enable powerdns

Now, PowerDNS-Admin is installed and configured. You can open your web browser and the URL http://example.com. You will be redirected to the PowerDNS-Admin web interface.

Conclusion

Congratulations! You have successfully installed and configured PowerDNS and PowerDNS-Admin on Ubuntu 18.04 server. We hope you have now enough knowledge to host your domain and zone records using PowerDNS-Admin web interface.

Any questions? Don´t hesitate to contact us. We´ll be happy to help you out 🙂

To write a comment on this article, fill out the form below. Fields marked with an asterisk (*) are required.

Visitors comments
  1. Comment (Published by Jaap)

    The line
    3 ExecStart=/opt/web/powerdns-admin/flask/bin/gunicor…..
    in /etc/systemd/system/powerdns.service
    gives an error, should that maybe be without 3 like this ?
    ExecStart=/opt/web/powerdns-admin/flask/bin/gunicor…..

    Reply

    • Comment (Published by cldn-kb-admin)

      Hi Jaap. Yes, the ‘3’ is to be left out. Thank you for your feedback!

      Reply