Installing PowerDNS

PowerDNS Logo
There are notes on installing PowerDNS on a CentOS 5 server. This is generic enough that it aught to work on any RPM based Linux distro with yum installed.

Preliminary Setup

  • Ensure BIND is not installed.
    $ sudo yum erase bind
    
  • Create a user to run as.
    $ sudo useradd -c "PowerDNS" -M -r -s /sbin/nologin pdns
    
  • Install MySQL
  • $ sudo yum install mysql-server
    $ sudo /sbin/service mysqld start
    $ sudo /sbin/chkconfig --level 35 mysqld on
    
  • Set MySQL root password. Please use different passwords.
    $ /usr/bin/mysqladmin -u root password 'new password'
    $ /usr/bin/mysqladmin -u root -h localhost password 'new password'
  • Run the following MySQL commands. Please change the passwords in the file first.
    $ mysql --user=root mysql -p
    Enter password:
    mysql> source database-install.sql;

    The database-install.sql is something I created. It has the following:

    ################################################################################
    #
    # Adjust users.
    #
    #  !!! WARNING !!!  Change the two passwords below!
    #
    ################################################################################
    
    # Change the root password here.
    UPDATE mysql.user SET password = PASSWORD('password') WHERE user = 'root';
    
    # Change the PowerDNS password here.
    CREATE USER 'powerdns'@'localhost' IDENTIFIED BY 'password';
    
    DROP USER '';
    FLUSH PRIVILEGES;
    
    ################################################################################
    #
    # Create database and tables.
    #
    ################################################################################
    CREATE DATABASE powerdns;
    
    USE 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          DEFAULT NULL,
    account         VARCHAR(40)  DEFAULT NULL,
    PRIMARY KEY (id)
    ) type=InnoDB;
    
    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)
    ) type=InnoDB;
    
    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
    ) type=InnoDB;
    
    GRANT ALL ON domains TO powerdns;
    GRANT ALL ON records TO powerdns;
    GRANT SELECT ON supermasters TO powerdns;

PowerDNS Setup

  • Download PowerDNS RPM.
  • Install RPM.
  • Change the permissions on the PowerDNS config file since it holds passwords in plain text.
    $ sudo chmod 440 /etc/powerdns/pdns.conf
  • Edit the PowerDNS config file.
    $ sudo vim /etc/powerdns/pdns.conf
  • Find the setgid and setuid lines. Add the appropriate lines
    setgid=pdns
    setuid=pdns
  • Find the launch line. Add information for the MySQL database.
    launch=gmysql
    gmysql-host=localhost
    gmysql-user=powerdns
    gmysql-password=password
    gmysql-dbname=powerdns
    gmysql-socket=/var/lib/mysql/mysql.sock
  • Find the local-address line and add the IP address of the publicly-facing NIC. See Chapter 15 of the documentation.
    local-address=xxx.xxx.xxx.xxx
  • Find the log-dns-details line and add the following:
    log-dns-details=off

Testing

  • Ensure that your firewall is allowing traffic on port 53 both UDP and TCP. If you do not, you’ll encounter strange errors with the DNS server not being found. (Ahem, yes, I did this recently.)
  • Test the setup by running PowerDNS in monitor mode:
    $ sudo /etc/init.d/pdns monitor
    
    Jan 04 22:46:34 This is a standalone pdns
    Jan 04 22:46:34 UDP server bound to 127.0.0.1:53
    Jan 04 22:46:34 TCP server bound to 127.0.0.1:53
    Jan 04 22:46:34 PowerDNS 2.9.21.2 (C) 2001-2008 PowerDNS.COM BV (Nov 16 2008, 14:07:43, gcc 4.2.3 (Ubuntu 4.2.3-2ubuntu7)) starting up
    Jan 04 22:46:34 PowerDNS comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it according to the terms of the GPL version 2.
    Jan 04 22:46:34 Set effective group id to 105
    Jan 04 22:46:34 Set effective user id to 102
    Jan 04 22:46:34 Creating backend connection for TCP
    Jan 04 22:46:34 gmysql Connection succesful
    Jan 04 22:46:34 About to create 3 backend threads for UDP
    Jan 04 22:46:34 gmysql Connection succesful
    Jan 04 22:46:34 gmysql Connection succesful
    Jan 04 22:46:34 gmysql Connection succesful
    Jan 04 22:46:34 Done launching threads, ready to distribute questions
  • If there are problems, see Chapter 4 of the documentation.
  • Test the operation. Leave the monitor (previous item) running. Pull up a new shell. Execute the following host command and look for a similar response.
    $ host www.test.com 127.0.0.1
    Using domain server:
    Name: 127.0.0.1
    Address: 127.0.0.1#53
    Aliases: 
    
    Host www.test.com not found: 2(SERVFAIL)

    In the monitor you should see the following message:

    Not authoritative for 'www.test.com', sending servfail to 127.0.0.1 (recursion was desired)
  • Add some test records to the database:
    $ mysql --user=root -p
    mysql> source database-test.sql;

    That file has the following commands, which I copied from the InterNet:

    USE powerdns;
    
    INSERT INTO domains (name, type) values ('test.com', 'NATIVE');
    INSERT INTO records (domain_id, name, content, type,ttl,prio) VALUES (1,'test.com','localhost ahu@ds9a.nl 1','SOA',86400,NULL);
    INSERT INTO records (domain_id, name, content, type,ttl,prio) VALUES (1,'test.com','dns-us1.powerdns.net','NS',86400,NULL);
    INSERT INTO records (domain_id, name, content, type,ttl,prio) VALUES (1,'test.com','dns-eu1.powerdns.net','NS',86400,NULL);
    INSERT INTO records (domain_id, name, content, type,ttl,prio) VALUES (1,'www.test.com','199.198.197.196','A',120,NULL);
    INSERT INTO records (domain_id, name, content, type,ttl,prio) VALUES (1,'mail.test.com','195.194.193.192','A',120,NULL);
    INSERT INTO records (domain_id, name, content, type,ttl,prio) VALUES (1,'localhost.test.com','127.0.0.1','A',120,NULL);
    INSERT INTO records (domain_id, name, content, type,ttl,prio) VALUES (1,'test.com','mail.test.com','MX',120,25);
  • Run the test again:
    $ host www.test.com 127.0.0.1
    Using domain server:
    Name: 127.0.0.1
    Address: 127.0.0.1#53
    Aliases:
    
    www.test.com has address 199.198.197.196
  • Try another test.
    $  host -v -t mx www.test.com 127.0.0.1
    Trying "www.test.com"
    Using domain server:
    Name: 127.0.0.1
    Address: 127.0.0.1#53
    Aliases: 
    
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 27585
    ;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0
    
    ;; QUESTION SECTION:
    ;www.test.com.			IN	MX
    
    ;; AUTHORITY SECTION:
    test.com.		86400	IN	SOA	localhost. ahu.ds9a.nl. 1 10800 3600 604800 3600
    
    Received 86 bytes from 127.0.0.1#53 in 21 ms
  • If you are receiving the following in the monitor:
    Authoritative empty NO ERROR to 127.0.0.1 for 'www.test.com' (AAAA), other types do exist.

    Then you did not put the log-dns-details=off in the configuration file. See the documentation, which says

    As the name implies, this is not an error. It tells you there are questions for a domain which exists in your database, but for which no record of the requested type exists. To get rid of this error, add log-dns-details=off to your configuration.

  • Remove the test records.
    $ mysql --user=root -p
    mysql> USE powerdns;
    mysql> DELETE FROM domains;
    mysql> DELETE FROM records;
  • Ensure pdns is set to run at boot time.
    $ sudo /sbin/chkconfig --level 35 pdns on
  • Start the services as a dæmon and you're done.
    $ sudo /etc/init.d/pdns start

Updates

2009-01-20
Fixed the section on local-address in the configuration file which prevented outside machines from accessing the name server.
2010-04-21
Fixed error caught by Matt. Thanks, Matt!
2011-01-22
Added a note to remind that port 53 must be opened for both TCP and UDP.
This entry was posted in SysAdmin and tagged , , , , , . Bookmark the permalink.

11 Responses to Installing PowerDNS

  1. Pingback: Setting Up Public Name Servers | James Reuben Knowles

  2. Mike says:

    anyluck setting up toplevel domains? I recently joined a vpn network, and i have tried to add a domain like .brd and well it doesn’t see it as a top level domain and refuses to add it.

    any ideas?

  3. Hey Mike,

    I’ve not tried to set up a TLD. I think this would be a perfect question for the PowerDNS mailing list. Have you tried the elist yet?

  4. Matt says:

    Nice article, very useful for a PowerDNS first timer! Worked right away on CentOS 5… Thanks!

    BTW, small error on the line : sudo yum /sbin/service mysqld start (yum?)

    Thanks!
    Matt.

  5. Matt,

    Thank you very much for catching that error! I’ve used these notes a couple of times and blew right past it.

    Glad you found it useful, and thanks again for the bug catch.
    James

  6. bayu says:

    why i can’n nslookup google.com when i install powerdns ?

    ** server can’t find google.com: SERVFAIL

    any suggestion ?

    thanks

  7. I would highly recommend you subscribe to the mailing. You can find more information on the PowerDNS wiki.

  8. Gareth says:

    Excellent starters guide, got it up and running in no time.

    Just a note if migrating from BIND 9, PowerDNS comes with a tool called ‘zone2sql’ which allows you to convert your BIND zones to gMYSQL format.
    Do something like…
    /usr/bin/zone2sql -gmysql –named-conf=

    You can also process individual zone files, as opposed to your entire conf file.

  9. That’s a great comment, Gareth. I’ve never had the need to migrate, but I’m sure it’s a common thing to do. Thanks!

  10. mars says:

    The test databse works great SOA comes right up. But when i try my real website SOA is missing. A and MX are all there. I Don’t get it and I want to. Any Ideas. Thanks!

  11. I’m not an expert on either DNS or PowerDNS unfortunately. It’s usually a small thing, like when I set up another server recently I forgot to open port 53 for UDP.

    I would highly recommend you subscribe to the mailing list and look on the PowerDNS wiki.

Leave a Reply