Salta ai contenuti

PowerDNS Cheat Sheet

Overview

PowerDNS is a high-performance authoritative DNS server that supports multiple database backends including PostgreSQL, MySQL/MariaDB, SQLite, LDAP, and BIND zone files. Unlike traditional DNS servers that read static zone files, PowerDNS can serve DNS records directly from a database, enabling dynamic DNS updates through its REST API or direct database manipulation. It supports DNSSEC out of the box with automatic key management, ALIAS records for zone apex CNAMEs, and Lua scripting for advanced record manipulation.

The PowerDNS ecosystem consists of three components: the Authoritative Server (pdns) for hosting authoritative zones, the Recursor (pdns-recursor) for recursive resolution, and dnsdist for DNS load balancing and traffic management. The authoritative server’s API allows full programmatic control over zones and records, making it ideal for automation, hosting platforms, and infrastructure-as-code workflows. PowerDNS handles billions of DNS queries per day in production at major hosting providers and DNS service operators worldwide.

Installation

Package Installation

# Ubuntu/Debian
sudo apt install pdns-server pdns-backend-pgsql

# Or with MySQL backend
sudo apt install pdns-server pdns-backend-mysql

# RHEL/CentOS
sudo dnf install pdns pdns-backend-postgresql

# Install PowerDNS tools
sudo apt install pdns-tools pdnsutil

# Start service
sudo systemctl enable pdns
sudo systemctl start pdns

Docker

docker run -d --name pdns \
  -p 53:53/tcp -p 53:53/udp -p 8081:8081 \
  -e PDNS_api=yes \
  -e PDNS_api_key=changeme \
  -e PDNS_webserver=yes \
  -e PDNS_webserver_address=0.0.0.0 \
  -e PDNS_webserver_port=8081 \
  -e PDNS_launch=gsqlite3 \
  -e PDNS_gsqlite3_database=/var/lib/powerdns/pdns.sqlite3 \
  powerdns/pdns-auth-48

Configuration

Main Config (/etc/powerdns/pdns.conf)

# General settings
daemon=yes
guardian=yes
setuid=pdns
setgid=pdns
local-address=0.0.0.0
local-port=53

# Backend
launch=gpgsql

# PostgreSQL backend
gpgsql-host=localhost
gpgsql-port=5432
gpgsql-dbname=powerdns
gpgsql-user=pdns
gpgsql-password=changeme

# API
api=yes
api-key=your-api-key-here
webserver=yes
webserver-address=0.0.0.0
webserver-port=8081
webserver-allow-from=127.0.0.1,10.0.0.0/8

# DNSSEC
default-soa-content=ns1.example.com hostmaster.@ 0 10800 3600 604800 3600

# Logging
loglevel=4
log-dns-queries=no
log-dns-details=no

# Performance
receiver-threads=4
distributor-threads=4
cache-ttl=60
query-cache-ttl=20
negquery-cache-ttl=60

Database Setup (PostgreSQL)

# Create database
sudo -u postgres createuser pdns
sudo -u postgres createdb -O pdns powerdns

# Initialize schema
sudo -u postgres psql powerdns < /usr/share/doc/pdns-backend-pgsql/schema.pgsql.sql

# Or for MySQL
mysql -u root -p -e "CREATE DATABASE powerdns; GRANT ALL ON powerdns.* TO 'pdns'@'localhost' IDENTIFIED BY 'changeme';"
mysql -u root -p powerdns < /usr/share/doc/pdns-backend-mysql/schema.mysql.sql

Core Commands (pdnsutil)

CommandDescription
pdnsutil create-zone <domain>Create a new zone
pdnsutil delete-zone <domain>Delete a zone
pdnsutil list-all-zonesList all zones
pdnsutil list-zone <domain>List records in a zone
pdnsutil add-record <domain> <name> <type> <content>Add a record
pdnsutil delete-rrset <domain> <name> <type>Delete a record set
pdnsutil edit-zone <domain>Interactive zone editor
pdnsutil check-zone <domain>Validate zone
pdnsutil check-all-zonesValidate all zones
pdnsutil rectify-zone <domain>Fix zone metadata
pdnsutil secure-zone <domain>Enable DNSSEC
pdnsutil show-zone <domain>Show zone metadata and keys
pdnsutil increase-serial <domain>Increment SOA serial

Zone Management

# Create a zone
pdnsutil create-zone example.com ns1.example.com

# Add records
pdnsutil add-record example.com . A 3600 203.0.113.10
pdnsutil add-record example.com . MX "3600 10 mail.example.com"
pdnsutil add-record example.com www A 3600 203.0.113.10
pdnsutil add-record example.com mail A 3600 203.0.113.20
pdnsutil add-record example.com . NS 3600 ns1.example.com
pdnsutil add-record example.com . NS 3600 ns2.example.com
pdnsutil add-record example.com ns1 A 3600 203.0.113.1
pdnsutil add-record example.com ns2 A 3600 203.0.113.2
pdnsutil add-record example.com . TXT '3600 "v=spf1 include:_spf.google.com ~all"'
pdnsutil add-record example.com _dmarc TXT '3600 "v=DMARC1; p=reject; rua=mailto:dmarc@example.com"'

# Add AAAA record
pdnsutil add-record example.com www AAAA 3600 2001:db8::1

# Delete a record
pdnsutil delete-rrset example.com www A

# Replace all records of a type
pdnsutil replace-rrset example.com www A 3600 203.0.113.11

# List zone contents
pdnsutil list-zone example.com

# Check zone validity
pdnsutil check-zone example.com

REST API

export PDNS_URL="http://localhost:8081"
export PDNS_API_KEY="your-api-key-here"

# List all zones
curl -s -H "X-API-Key: $PDNS_API_KEY" \
  "$PDNS_URL/api/v1/servers/localhost/zones" | jq '.[].name'

# Get zone details
curl -s -H "X-API-Key: $PDNS_API_KEY" \
  "$PDNS_URL/api/v1/servers/localhost/zones/example.com." | jq

# Create a zone
curl -X POST -H "X-API-Key: $PDNS_API_KEY" \
  -H "Content-Type: application/json" \
  "$PDNS_URL/api/v1/servers/localhost/zones" \
  -d '{
    "name": "newdomain.com.",
    "kind": "Native",
    "nameservers": ["ns1.example.com.", "ns2.example.com."]
  }'

# Add/Update records (PATCH)
curl -X PATCH -H "X-API-Key: $PDNS_API_KEY" \
  -H "Content-Type: application/json" \
  "$PDNS_URL/api/v1/servers/localhost/zones/example.com." \
  -d '{
    "rrsets": [
      {
        "name": "app.example.com.",
        "type": "A",
        "ttl": 300,
        "changetype": "REPLACE",
        "records": [
          {"content": "10.0.1.10", "disabled": false},
          {"content": "10.0.1.11", "disabled": false}
        ]
      }
    ]
  }'

# Delete a record set
curl -X PATCH -H "X-API-Key: $PDNS_API_KEY" \
  -H "Content-Type: application/json" \
  "$PDNS_URL/api/v1/servers/localhost/zones/example.com." \
  -d '{
    "rrsets": [
      {
        "name": "old.example.com.",
        "type": "A",
        "changetype": "DELETE"
      }
    ]
  }'

# Notify secondaries
curl -X PUT -H "X-API-Key: $PDNS_API_KEY" \
  "$PDNS_URL/api/v1/servers/localhost/zones/example.com./notify"

DNSSEC

# Secure a zone
pdnsutil secure-zone example.com

# Show DNSSEC keys
pdnsutil show-zone example.com

# Export DS records (for registrar)
pdnsutil export-zone-ds example.com

# Key rollover
pdnsutil add-zone-key example.com ksk active 2048
pdnsutil deactivate-zone-key example.com <old-key-id>

# Rectify zone (fix NSEC/NSEC3 chains)
pdnsutil rectify-zone example.com

# Set NSEC3
pdnsutil set-nsec3 example.com '1 0 10 abcd' narrow

# Unset NSEC3 (use NSEC)
pdnsutil unset-nsec3 example.com

Advanced Usage

Zone Transfer (AXFR/IXFR)

# pdns.conf - allow zone transfers
allow-axfr-ips=10.0.0.0/8
also-notify=10.0.0.2,10.0.0.3

# Per-zone metadata
pdnsutil set-meta example.com ALLOW-AXFR-FROM 10.0.0.2/32
pdnsutil set-meta example.com ALSO-NOTIFY 10.0.0.2:53

Lua Records (Dynamic DNS)

# Add Lua record for geographic load balancing
pdnsutil add-record example.com www LUA "A \"ifportup(443, {'10.0.1.1','10.0.2.1','10.0.3.1'})\""

# Weighted responses
pdnsutil add-record example.com www LUA "A \"pickwhashed({10, '10.0.1.1', 5, '10.0.2.1'})\""

# Health-checked failover
pdnsutil add-record example.com api LUA "A \"ifurlup('https://10.0.1.1/health', {'10.0.1.1','10.0.2.1'})\""

Secondary (Slave) Zone

# Create secondary zone
pdnsutil create-secondary-zone example.org 10.0.0.100

# Or via API
curl -X POST -H "X-API-Key: $PDNS_API_KEY" \
  -H "Content-Type: application/json" \
  "$PDNS_URL/api/v1/servers/localhost/zones" \
  -d '{
    "name": "example.org.",
    "kind": "Slave",
    "masters": ["10.0.0.100"]
  }'

Troubleshooting

IssueSolution
Unable to launch backendCheck database connection settings in pdns.conf; verify schema is initialized
SERVFAIL on queriesRun pdnsutil check-zone <domain>; ensure SOA and NS records exist
API returns 401Verify api-key in pdns.conf matches your request header
DNSSEC validation failingRun pdnsutil rectify-zone <domain>; verify DS records at registrar
Zone transfer not workingCheck allow-axfr-ips setting; verify NOTIFY is configured
Slow query performanceEnable query cache; check database indexes; increase receiver-threads
Lua records not resolvingEnsure Lua backend is compiled in; check Lua syntax in record