Running PowerDNS in docker-compose

PowerDNS is easily installed and run on most servers, whether you’re using it as an authoritative server or a recursor. To better understand the difference, check out this blog.

Basically your authoritative server has the actual DNS info you’re looking for or providing (usually an IP), and your recursive server is the one finding the path to the right server and caching any previously checked information.

Checking out PowerDNS

While most other nameservers combine recursive and authoritative functions, PowerDNS or pdns comes in two flavours (pdns-auth and pdns-recursor). Trying it out by installing the binaries is easy enough with the installation docs. The default comes with a bind backend, but in this example we’re using sqlite3 instead.

So for the containerized version, all we need is a server with:

  • docker
  • docker-compose
  • port 53 (and potentially 8081/8082 if you want to contact pdns via API) open

We start with the docker-compose.yaml file:

# based on https://github.com/PowerDNS/pdns
---
version: '2.0'
services:
  recursor:
    image: powerdns/pdns-recursor-45:4.5.5 # the latest pdns-recursor from dockerhub
    # the forward-zones are used to make sure the recursor asks the local authoritative server 
    # about our own domains
    command: --forward-zones=<domain>=172.25.0.2:5300 --local-address=0.0.0.0 --local-port=53 
    environment:
      - PDNS_RECURSOR_API_KEY
    ports:
      - "53:53"
      - "53:53/udp"
      - "8082:8082" # HTTP API for the recursor

  auth:
    image: powerdns/pdns-auth-45:4.5.1 # latest pdns-authoritative nameserver image
    command: --local-address=0.0.0.0 --local-port=5300
    user: root
    environment:
      - PDNS_AUTH_API_KEY
    ports:
      - "5300:5300" # this is the port we redirect queries to above
      - "5300:5300/udp"
      - "8081:8081" # HTTP API of the server
    volumes:
      - /var/lib/powerdns/pdns.sqlite3:/var/lib/powerdns/pdns.sqlite3
    networks:
      default:
        ipv4_address: 172.25.0.2

networks:
  default:
    driver: bridge
    ipam:
      config:
        # defining the network range and IP for the authoritative server is only necessary in 
        # specific cases (e.g. to avoid breaking networking on some servers, most do fine without)
        - subnet: 172.25.0.0/16

Initializing the database

Before running pdns, the sqlite database needs to be created.

mkdir /var/lib/powerdns
sqlite3 -init schema.sql /var/lib/powerdns/pdns.sqlite3

Where schema.sql is taken from here.

Environment variables for API access

To enable the API access to pdns, make sure you have the following environment variables set:

export PDNS_RECURSOR_API_KEY=changeme
export PDNS_AUTH_API_KEY=changeme

Starting the containers is as simple as running docker-compose up -d in the folder where the above YAML file is.

Testing

Check if your containers are successfully running with docker-compose ps -a. If they’re up, you can test the service using

curl -v -H 'X-API-Key: changeme' http://<serverIP>:8081/api/v1/servers/localhost/ | jq

To add zones to the authoritative server you can use pdnsutil or the API.

To check if you’ve successfully added a zone or record, you can check with either

nslookup <domain> <serverIP>

or

dig <domain> @serverIP

Adding a --port 5300 to the dig command, let’s you test the authoritative server directly.