Bind9 has treated us well over the years, but its lack of support for database back ends in a default install is very annoying, especially when an application needs to control DNS services dynamically. PowerDNS is a powerful alternative it supports a wide variety of back ends and can also be configured to serve different records dependant on the clients Geographical location making it a valuable asset in these coming days of private clouds gaining traction.
This article will walk you through the process of setting up a PowerDNS server with a replicated MySQL back end on two Ubuntu 9.10 systems.
Step 1 – Configuring the Master Nameserver
This nameserver is going to be your primary server, any changes that need to be made to the DNS records are made on this server and they will be replicated on the the slave. To get started log into your primary name server via SSH and execute:
apt-get update
apt-get install apt-get install pdns-server pdns-backend-mysql mysql-server
When prompted by the installer create a password for the MySQL root user and then configure the MySQL service itself:
pico /etc/mysql/my.cnf
Go down to line 53, it should look like the line below comment it out.
bind-address = 127.0.0.1 <- becomes -> # bind-address = 127.0.0.1
This is needed so the slave server can talk to the master and be aware of any changes made to its records. Save the file, then restart the MySQL service to make your changes active.
/etc/init.d/mysql restart
Okay now its time to sort out the database side of things by creating a MySQL user for PowerDNS to use and the database for the storage of its DNS records:
mysql -u root -p
Whilst in the MySQL client execute the following commands:
CREATE DATABASE dns_server;
GRANT ALL ON dns_server.* TO ‘pdns’@’localhost’ IDENTIFIED BY ‘pdns_pass’;
NOTE: Be sure to change the password for the pdns user to something a tad stronger.
GRANT ALL ON dns_server.* TO ‘pdns’@’localhost.localdomain’ IDENTIFIED BY ‘pdns_pass’;
FLUSH PRIVILEGES;
USE dns_server;
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 DEFAULT NULL,
account VARCHAR(40) DEFAULT NULL,
primary key (id)
);
CREATE UNIQUE INDEX name_index ON domains(name);
CREATE TABLE records (
id INT auto_increment,
domain_id INT DEFAULT NULL,
name VARCHAR(255) DEFAULT NULL,
type VARCHAR(6) DEFAULT NULL,
content VARCHAR(255) DEFAULT NULL,
ttl INT DEFAULT NULL,
prio INT DEFAULT NULL,
change_date INT DEFAULT NULL,
primary key(id)
);
CREATE INDEX rec_name_index ON records(name);
CREATE INDEX nametype_index ON records(name,type);
CREATE INDEX domain_id ON records(domain_id);
CREATE TABLE supermasters (
ip VARCHAR(25) NOT NULL,
nameserver VARCHAR(255) NOT NULL,
account VARCHAR(40) DEFAULT NULL
);
Then exit the MySQL client with the command:
exit;
Alternatively if you don’t feel that comfortable using the command line MySQL client you could install phpmyadmin and use that to create the database and user within web based environment.
Now that the database has been setup we need to configure PowerDNS to use our newly created MySQL database and user for any lookups it needs to make.
pico /etc/powerdns/pdns.conf
Go down to line 82 or thereabouts and find the line:
# launch=
Uncomment this line and modify so that it reads:
launch=gmysql
Edit the file /etc/powerdns/pdns.d/pdns.local
:
pico /etc/powerdns/pdns.d/pdns.local
Add the following lines so that PowerDNS can connect with the MySQL service.
gmysql-host=127.0.0.1
gmysql-user=pdns
gmysql-password=pdns_pass
gmysql-dbname=dns_server
Save the file and its show time, just restart the PowerDNS service for your changes to take effect and the DNS side of your server should be good to go!
/etc/init.d/pdns restart
Step 2 – Setting up PowerAdmin
Okay its working but not very useful at the present, as it has no DNS records to serve. So lets install PowerAdmin so we can manage our DNS records using a web based interface. I am assuming the server you are working on already has Apache2, PHP and its modules installed already. If this is not the case you will need to install these before continuing as they are required for the operation PowerAdmin.
PowerAdmin also requires the mdb2 module to work properly, which i doubt many people will have installed already. So:
apt-get install php-mdb2-driver-mysql
Or on some older versions of Ubuntu it wont be in the repository so make sure you have PEAR installed and
apt-get install php-pear
pear install MDB2-2.5.0b2
pear install MDB2_Driver_mysql-1.5.0b2
Then continue the poweradmin install with:
cd /tmp
wget https://www.poweradmin.org/download/poweradmin-2.1.3.tgz
tar zxvf poweradmin-2.1.3.tgz
mv poweradmin-2.1.3 /var/www/poweradmin
cd /var/www/poweradmin
Now the code base is in place open your browser and point it at the Poweradmin location to continue the install process e.g http://ns1.mydomain.com/poweradmin/install
Follow the install instructions and when you reach step 6 of the install process copy the PHP code displayed on screen, go back to your terminal window create the file:
pico /var/www/poweradmin/inc/config.inc.php
Then paste the code from the browser window into the new file and save.
NOTE: The browser gives you the code with white space between some of the lines make sure these have been removed before saving the file. Otherwise after logging in you will be greeted by a “Warning: Cannot modify header information” PHP error.
Step 7 is the last step of the install process and simply asks you to delete the install directory. If you fail to complete this step, the program will not let you login!
rm -rf /var/www/poweradmin/install
The operation of PowerAdmin is pretty straight forward although if you have only used Bind in the past you may find some of the terms a little confusing. A quick look at the PowerDNS documentation should point you in the right direction though.
Step 3 – Replicating Changes on the Slave Server
Log in to the server you will be using as your MySQL slave. Update the repositories and then install the MySQL server application:
apt-get update
apt-get install mysql-server
On your master server edit the /etc/mysql/my.cnf file go down to around line 92. Uncomment and modify the lines that regard replication so they resemble:
server-id = 1
log_bin = /var/log/mysql/mysql-bin.log
expire_logs_days = 10
max_binlog_size = 100M
binlog_do_db = dns_server
Save your changes to the file and then open up the MySQL client to create a new user for the replication process:
CREATE USER ‘replication_user’@’192.168.0.2’ IDENTIFIED BY ‘mypassword’;
GRANT REPLICATION SLAVE ON * . * TO ‘replication_user’@’192.168.0.2’ IDENTIFIED BY ‘mypassword’;
NOTE: replace the IP address ‘192′.168.0.2‘ with the IP of your slave server, and change the password to something a bit stronger than ‘mypassword‘
Now edit the /etc/mysql/my.cnf file of your slave server and append the following lines after the [mysqld] declaration so that the slave can connect to its master:
server-id=2
master-host = 192.168.0.1
master-user = replication_user
master-password = mypassword
master-port = 3306
Be sure to change the ip address of the master server and the users password to match your setup. Save the file and restart the MySQL service on both the Master and Slave nodes so that your changes will take effect.
On the slave now use the mysql command line tool and execute the following commands:
start slave;
show slave statusG;
You you should see something like:
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.0.1
Master_User: replication_user
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysqld-bin.000001
Read_Master_Log_Pos: 98
Relay_Log_File: mysqld-relay-bin.000002
Relay_Log_Pos: 236
Relay_Master_Log_File: mysqld-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 98
Relay_Log_Space: 236
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
1 row in set (0.00 sec)
Now test it by creating a record on the master and with any luck you will also be able to see it on the slave. That said i stuffed around a bit when setting mine up and the slave service wouldn’t start as it was looking for the wrong bin file on the master. I was able to follow these instructions though to point the slave in the right direction to get it working again.