Architecture: authoritative vs recursive
Two roles for a nameserver:
- Authoritative — "I am the source of truth for example.com." Answers queries about zones it hosts; refuses anything else.
- Recursive — "I resolve queries by walking the DNS hierarchy." Cache, talks to root + TLD + authoritative servers on behalf of clients.
PowerDNS has separate daemons for each: pdns_server (authoritative) and pdns_recursor (recursive). This tutorial covers the authoritative one. For the recursive role, see Pi-hole + Unbound; Unbound is the simpler recursive option.
Install
# Debian / Ubuntu
sudo apt install pdns-server pdns-backend-pgsql
# Or use the upstream PowerDNS apt repo for newer versions
# https://repo.powerdns.com/
# Create the database
sudo -u postgres createuser --pwprompt pdns
sudo -u postgres createdb -O pdns pdns
# Initialize the schema
psql -h /var/run/postgresql -U pdns -d pdns -f \
/usr/share/pdns-backend-pgsql/schema/schema.pgsql.sql
Configuration
Edit /etc/powerdns/pdns.conf:
launch=gpgsql
gpgsql-host=127.0.0.1
gpgsql-port=5432
gpgsql-dbname=pdns
gpgsql-user=pdns
gpgsql-password=<pw>
# Listen on all interfaces (or pick specific)
local-address=0.0.0.0,::
# Enable the REST API
api=yes
api-key=<long-random-string>
# Webserver for the API (and stats)
webserver=yes
webserver-address=127.0.0.1
webserver-port=8081
webserver-allow-from=127.0.0.1,::1
# Allow zone transfers only to specific secondaries
# allow-axfr-ips=192.0.2.1,2001:db8::1
# Disable version reporting (defence-in-depth)
version-string=anonymous
disable-axfr-rectify=no
sudo systemctl restart pdns
sudo systemctl status pdns
sudo journalctl -u pdns -f
Create a zone via the API
# Create zone example.com
curl -X POST -H "X-API-Key: <api-key>" \
-H "Content-Type: application/json" \
-d '{
"name": "example.com.",
"kind": "Master",
"masters": [],
"nameservers": ["ns1.example.com.", "ns2.example.com."]
}' \
http://localhost:8081/api/v1/servers/localhost/zones
# Add an A record
curl -X PATCH -H "X-API-Key: <api-key>" \
-H "Content-Type: application/json" \
-d '{
"rrsets": [{
"name": "www.example.com.",
"type": "A",
"ttl": 3600,
"changetype": "REPLACE",
"records": [{ "content": "203.0.113.10", "disabled": false }]
}]
}' \
http://localhost:8081/api/v1/servers/localhost/zones/example.com.
# AAAA, MX, TXT, CNAME, etc. all follow the same shape
Always include the trailing dot in zone and record names — FQDN form. The API is strict about this.
The CLI: pdnsutil
For one-off operations without the API:
# Create a zone
sudo pdnsutil create-zone example.com ns1.example.com
# Add records
sudo pdnsutil add-record example.com www A 3600 203.0.113.10
sudo pdnsutil add-record example.com mail A 3600 203.0.113.11
sudo pdnsutil add-record example.com @ MX 3600 "10 mail.example.com."
sudo pdnsutil add-record example.com @ TXT 3600 '"v=spf1 ip4:203.0.113.0/24 -all"'
# Inspect
sudo pdnsutil list-all-zones
sudo pdnsutil list-zone example.com
# Edit a zone in $EDITOR
sudo pdnsutil edit-zone example.com
DNSSEC: signing the zone
PowerDNS does DNSSEC online — on-the-fly signing of responses, with keys stored in the database. Two-step setup:
# Enable DNSSEC for the zone
sudo pdnsutil secure-zone example.com
# Show the DS record to upload to the parent zone (your registrar)
sudo pdnsutil show-zone example.com
The output includes the DNSKEY records (in the zone) and the DS (Delegation Signer) records that must be uploaded to the registrar to chain trust from the root. After the registrar publishes the DS, the chain validates and any DNSSEC-aware resolver returns AD-flagged answers.
Key roll-overs (rotate ZSK or KSK every 6–12 months) are scripted:
# Add a new ZSK alongside the old one
sudo pdnsutil add-zone-key example.com zsk active rsasha256 2048
# After waiting (TTL), remove the old one
sudo pdnsutil remove-zone-key example.com <old-key-id>
Secondary nameservers
For real authoritative service, you want at least two nameservers on different networks. PowerDNS supports the standard AXFR / IXFR zone-transfer protocol:
On the primary — allow AXFR + add a NOTIFY peer:
allow-axfr-ips=203.0.113.20
also-notify=203.0.113.20
On the secondary — configure it as a Slave for the zone (via API or pdnsutil), pointing at the primary's IP. When a record changes, the primary sends a NOTIFY; the secondary pulls the updated zone via AXFR/IXFR.
Or, if your secondaries are someone else's infrastructure (BuddyNS, NS1 secondary service, etc.), they handle the AXFR themselves — you just need to allow it.
PowerDNS-Admin: the web UI
The official daemon has only a REST API; for a web UI, install PowerDNS-Admin (a separate Python/Flask app):
docker run -d \
--name pdns-admin \
--restart unless-stopped \
-p 127.0.0.1:9191:80 \
-e SECRET_KEY="<random>" \
-e SQLA_DB_HOST=db \
-e SQLA_DB_USER=pdnsadmin \
-e SQLA_DB_PASSWORD=<pw> \
-e SQLA_DB_NAME=pdnsadmin \
powerdnsadmin/pda-legacy:latest
First-run wizard creates the admin account, asks for the PowerDNS API URL and key, then provides a web UI for zone / record management, audit log, RBAC, and DNSSEC controls.
Hardening for an internet-facing nameserver
- Hide the API. Bind the webserver to
127.0.0.1; never expose the API port publicly. Reach it via SSH tunnel or a reverse proxy with auth. - Use anycast. For real production, route the same DNS server IP from multiple regions via BGP anycast. Beyond a homelab, but the architecture matters.
- Rate-limit. The
lua-recordsmodule supports rate-limit logic per query type; or front PowerDNS withdnsdist(PowerDNS's own DNS load balancer) for per-source rate limits and DDoS-mitigation primitives. - Monitor. Scrape the Prometheus exporter (PowerDNS exposes /metrics natively in recent versions). Alert on query rate, error rate, AXFR refusals.
When PowerDNS is the wrong tool
- For "I just need DNS records for my domains and someone else to operate the servers" — Cloudflare, Route 53, or DigitalOcean Networking are easier and free at homelab scale.
- For "I need a recursive resolver for my LAN" — Unbound (see that tutorial) is the right tool, not PowerDNS Authoritative.
- For pure-text-file BIND-style operation — Knot DNS or NSD might fit better; PowerDNS's strength is the API + DB backend pattern.
For "I run my own authoritative DNS for my domains and want a programmable, database-backed nameserver with first-class DNSSEC," PowerDNS is the canonical choice in the 2026 self-hosted landscape.