Implementing PowerDNS in the Homelab

For a while now I have been relying solely on the Unifi built in DNSMasq resolver for my internal DNS. It’s great and I like that it runs independantly of my Proxmox lab cluster setup to ensure that maintenance on that cluster doesn’t interrupt Prod YouTube for the household. Recently, however, I have come across a couple of use cases that I can’t accomodate with DNSMasq on Unifi; Proxmox SDN integrated DNS and ACME.sh Challenge handling which both require an HTTP API.

This is where PowerDNS comes in. I don’t know a lot about it yet but it seems to me like a powerfull wrapper around bind which allows you to use non-bindfile backends (like MariaDB) and wraps everything up in a nice HTTP API.

Update 11-09-24

So I told you I didn’t know much about PowerDNS. What I have now learned has changed the architecture a little. PowerDNS seperates the role of authoritative name server and recursive resolver into two seperate binaries. I discovered this when I setup a CNAME record in my PowerDNS zone to a record in my DNSMasq resolver on the USG. As my PowerDNS was only confugred to be an authoritative name server, it wasn’t able to expand the CNAME record and enumerate the host that the record was pointing to. I stumbled onto this page https://doc.powerdns.com/authoritative/guides/recursion.html and decided upon implemented Scenario 1.

PowerDNS Authoritative Name Server binds to 127.0.0.1:5353 as the authoritative name server for int.etse.me. PowerDNS Recursor binds to 192.168.254.2:53 as the recursive resolver.

  • Install the package sudo apt install pdns-recursor
  • Configure the PowerDNS Recusror to bind to 192.168.254.2 on port 53.
  • Configure the PowerDNS Recusror to use a forward zones config file.

>cat /etc/powerdns/recursor.conf

local-address=192.168.254.2
local-port=53
forward-zones-file=/etc/powerdns/forward-zones.txt

>cat /etc/powerdns/forward-zones.txt

int.etse.me=127.0.0.1:5353 # the local authoritative PowerDNS instance
# DNSMasq on the USG forward records
mgmt.etse.me=192.168.254.1 
iot.etse.me=192.168.254.1
guest.etse.me=192.168.254.1
house.etse.me=192.168.254.1
dmz2.etse.me=192.168.254.1
dmz3.etse.me=192.168.254.1
sdn.etse.me=192.168.254.1
nst.etse.me=192.168.0.1

# DNSMasq on the USG PTR records
254.168.192.in-addr.arpa=192.168.254.1
254.10.in-addr.arpa=192.168.254.1
192.10.in-addr.arpa=192.168.254.1
64.10.in-addr.arpa=192.168.254.1
2.168.192.in-addr.arpa=192.168.254.1
3.168.192.in-addr.arpa=192.168.254.1
254.168.192.in-addr.arpa=192.168.254.1
1.168.192.in-addr.arpa=192.168.1.1

Pre-requisites

  • Debian 12 LXC Container 1 core, 512MB RAM, 512MB Swap, 16GB HDD (Unprivileged)
  • Shared MariaDB Server in the lab (this may turn out to be a bad choice but we will see)

Prepare your container

Start with…

>sudo apt update
>sudo apt dist-upgrade -y

Install PowerDNS packages

>sudo apt install pdns-server pdns-backend-mysql # mysql is binary compatible with mariadb which I use.

Configure your MariaDB / MySQL

>sudo mysql -u root -p
Password: *********

Create the database and MariaDB user for access.

MariaDB [(none)]>create database powerdns;
MariaDB [(none)]>create user pdns@pdns.mgmt.etse.me identified by 'secret-password'; # the domain part of this user should be based on the source of authentication.  In this case, the PowerDNS server.
MariaDB [(none)]>grant all privileges on powerdns.* to pdns@pdns.mgmt.etse.me; 
MariaDB [(none)]>flush privileges; # is this still needed? NFI
MariaDB [(none)]>quit;

Copy the PowerDNS schema from the bottom of this page into a file pdns.sql.

Now load the PowerDNS schema into the database.

>sudo mysql -u root -D powerdns < pdns.sql

Configure PowerDNS to use your MariaDB backend

cat <<EOF > /etc/powerdns/pdns.d/mysql.conf
gmysql-host=mariadb.mgmt.etse.me
gmysql-dbname=powerdns
gmysql-user=pdns
gmysql-password=secret-password
EOF

Configure some basic settings for PowerDNS

PowerDNS is a very advanced name server and supports everything you could want. For our purposes right now, we are simply going to enable the Authoritative Name Server, Web Server and API.

>grep -v "^#" /etc/powerdns/pdns.conf
api=yes
api-key=secret-api-key

# Set this before you create your first zone as each zone inherrits the config for its SOA record
default-soa-content=pdns.mgmt.etse.me hostmaster.@ 0 10800 3600 604800 3600

include-dir=/etc/powerdns/pdns.d

launch=gmysql # Use the MySQL Backend

security-poll-suffix=

webserver=yes
webserver-address=192.168.254.2 # Local address to bind webserver and API too.
webserver-allow-from=192.168.0.0/16,10.0.0.0/8
webserver-password=secret
webserver-port=8081

Start PowerDNS Service

>sudo systemctl start pdns.service

Add your first zone

To create your first zone, use the command sudo pdnsutil create-zone int.etse.me. Now add some new records to the zone - an NS record to identify the nameservers for this domain. And a bogus A record which we can use to test resolution.

sudo pdnsutil add-record int.etse.me @ NS 192.168.254.2
sudo pdnsutil add-record int.etse.me test A 192.168.254.101

Let’s test it all out!

➜  ~    dig NS int.etse.me @192.168.254.2

; <<>> DiG 9.10.6 <<>> NS int.etse.me @192.168.254.2
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 6012
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;int.etse.me.			IN	NS

;; ANSWER SECTION:
int.etse.me.		3600	IN	NS	192.168.254.2.

;; Query time: 8 msec
;; SERVER: 192.168.254.2#53(192.168.254.2)
;; WHEN: Sun Sep 08 21:29:10 AWST 2024
;; MSG SIZE  rcvd: 69

and…

➜  ~ dig +short test.int.etse.me @192.168.254.2
192.168.254.101

Fit it into the homelab DNS

For my use case, I am going to maintain the DNSMasq as the root resolver for Internal DNS and tell it to use the PowerDNS resolver to find hosts in the int.etse.me zone.

To make the required change on Unifi DNSMasq, simply add thw line below to your options array. If you need some help getting the Unifi DNSMasq up and running, see: https://etse.me/tech/unifi/dns/2019/09/20/Unifi-Internal-DNS.html

{
  "options": [
    "server=/int.etse.me/192.168.254.2"
  ]
}

Conclusion

This is very much a getting up and running with PowerDNS guide, hopefully it is useful ☺️


© 2021. All rights reserved.

Powered by Hydejack v9.1.6