Networking Azure

PowerDNS Recursor on Ubuntu 24.04 on Azure User Guide

| Product: PowerDNS Recursor 5.3 on Ubuntu 24.04 LTS on Azure

Overview

This guide covers the deployment and configuration of PowerDNS Recursor on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. PowerDNS Recursor is a high performance, standards compliant open source recursive DNS resolver developed by PowerDNS.COM BV. Unlike an authoritative server, which publishes the zones you own, a recursor resolves names on behalf of your clients: it walks the DNS hierarchy from the root servers down, follows delegations, validates DNSSEC signed answers, and caches results so repeat lookups are answered instantly.

The image installs PowerDNS Recursor 5.3 from the official PowerDNS packages (the repo.powerdns.com rec 53 stable branch), pinned above the distribution package. Unattended security upgrades are configured to keep the resolver patched on your running VM.

Recursive, not authoritative. This server resolves names for your clients; it does not publish zones. It is the resolver you point your workloads, containers and office networks at instead of a public resolver, keeping your DNS traffic private and under your control.

Never an open resolver — secure by default. An internet facing resolver that answers anyone is a DNS amplification hazard. This image ships with recursion restricted to loopback and the RFC1918 private ranges only (incoming.allow_from). Queries from arbitrary internet sources are refused, so this instance can never be abused as a reflector. Opening the resolver to your own client subnets is a single documented change (Step 8).

Security by design — no default credentials. The REST API key is the equivalent of an administrator password for the resolver, so this image never ships a fixed key. On the very first boot of every VM a fresh per instance REST API key and a fresh webserver password are generated, and the details are written to /root/powerdns-recursor-credentials.txt (mode 0600, root only). The REST API and status webserver are bound to 127.0.0.1 only, so the management surface is never exposed to the network while DNS resolution answers on port 53 for your allowed clients.

What is included:

  • PowerDNS Recursor 5.3 from the official PowerDNS packages, run under systemd as the unprivileged pdns user (pdns-recursor.service)

  • Recursion restricted to loopback and RFC1918 private ranges by default (incoming.allow_from) so the instance is never an open resolver

  • DNSSEC validation of signed answers, and the systemd-resolved stub listener disabled so the Recursor owns port 53 cleanly

  • The REST API enabled and bound to loopback (127.0.0.1:8082), authenticated with a per instance X-API-Key, plus the status webserver

  • A per instance REST API key and webserver password generated on first boot, documented in /root/powerdns-recursor-credentials.txt (0600)

  • YAML settings (PowerDNS Recursor 5.x native format) with the cloudimg configuration split into a base drop-in and a per VM secrets drop-in under /etc/powerdns/recursor.d/

Prerequisites

  • Active Azure subscription, SSH public key, VNet + subnet in target region

  • Subscription to the PowerDNS Recursor listing on Azure Marketplace

  • Network Security Group rules allowing TCP 22 (admin) and both UDP and TCP 53 (DNS) from the client networks that will use the resolver

Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) for a small resolver. Resolvers serving heavy query volumes should use Standard_D2s_v5 or larger.

Step 1: Deploy from the Azure Portal

Search PowerDNS Recursor in Marketplace, select the cloudimg publisher, and click Create. Configure the Network Security Group to allow UDP 53 and TCP 53 (DNS) from your client networks, and TCP 22 for administration. DNS uses UDP 53 for most queries and falls back to TCP 53 for large responses, so open both. The REST API stays on loopback and is never exposed.

Step 2: Deploy from the Azure CLI

RG="dns-prod"; LOCATION="eastus"; VM_NAME="resolver1"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/powerdns-recursor-ubuntu-24-04/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az vm create \
  --resource-group "$RG" --name "$VM_NAME" \
  --image "$GALLERY_IMAGE_ID" \
  --size Standard_B2s \
  --admin-username azureuser \
  --ssh-key-values "$SSH_KEY" \
  --public-ip-sku Standard
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 53 --priority 1001
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 22 --priority 1002

Step 3: First boot

On first boot the image generates a fresh per instance REST API key and webserver password, starts pdns-recursor, verifies the API key round trips and a real recursive query resolves, and writes /root/powerdns-recursor-credentials.txt. This completes within a minute. SSH in as azureuser and read the details:

sudo cat /root/powerdns-recursor-credentials.txt

Step 4: Confirm the service is running

pdns-recursor.service (the resolver daemon) is active. ss confirms DNS is listening on :53 (UDP and TCP, all interfaces) while the REST API is bound to 127.0.0.1:8082 only.

systemctl is-active pdns-recursor.service
pdns_recursor --version 2>&1 | head -1
ss -tlnup | grep -E ':53 |:8082 '

pdns-recursor.service is active, pdns_recursor reports PowerDNS Recursor 5.3.8, and ss shows DNS listening on port 53 udp and tcp on all interfaces while the REST API is bound to 127.0.0.1 port 8082 loopback only

Step 5: Resolve a name

The resolver answers recursive queries for allowed clients. Loopback is allowed by default, so a lookup works immediately on the VM. Because the Recursor caches answers, a repeated query is served instantly from cache.

dig @127.0.0.1 A example.com +noall +answer
dig @127.0.0.1 AAAA cloudflare.com +short
dig @127.0.0.1 MX gmail.com +short

dig against the local Recursor resolves example.com to a public A record, cloudflare.com to its AAAA addresses, and gmail.com MX records, proving the resolver recurses to the internet on behalf of the client

Step 6: Use the REST API

The REST API exposes metrics and cache management and is the same interface automation tools use. Read your per instance API key from the credentials file into a shell variable, then call the server info endpoint. It is bound to loopback, so run these on the VM (or tunnel port 8082 over SSH).

API_KEY=$(sudo grep '^powerdns.api.key=' /root/powerdns-recursor-credentials.txt | cut -d= -f2-)
curl -s -H "X-API-Key: $API_KEY" http://127.0.0.1:8082/api/v1/servers/localhost | jq '{daemon_type, version}'
sudo rec_control get-all | grep -E '^(questions|cache-hits|cache-misses|cache-entries|all-outqueries)\b'

A request without the key is rejected with HTTP 401, and a request with the key returns HTTP 200:

API_KEY=$(sudo grep '^powerdns.api.key=' /root/powerdns-recursor-credentials.txt | cut -d= -f2-)
echo -n 'with key    : HTTP '; curl -s -o /dev/null -w '%{http_code}\n' -H "X-API-Key: $API_KEY" http://127.0.0.1:8082/api/v1/servers/localhost
echo -n 'wrong key   : HTTP '; curl -s -o /dev/null -w '%{http_code}\n' -H 'X-API-Key: wrong-key' http://127.0.0.1:8082/api/v1/servers/localhost

the REST API server info endpoint returns JSON with daemon_type recursor and version 5.3.8 when called with the per VM X-API-Key, rec_control reports live query and cache statistics, and an authenticated request returns HTTP 200 while a request with a wrong key returns HTTP 401

Step 7: Review the secure by default configuration

No default or shared credentials ship in the image. The credentials file is 0600 root:root, the API key and webserver password are unique to this VM, and the resolver is not an open resolver: incoming.allow_from is restricted to loopback and RFC1918 private ranges, and the REST API is bound to loopback only.

sudo stat -c '%n  perms: %a  owner: %U:%G' /root/powerdns-recursor-credentials.txt
sudo grep -vE '^\s*#|^\s*$' /etc/powerdns/recursor.d/cloudimg-recursor.yml
sudo stat -c '%n  perms: %a  owner: %U:%G' /etc/powerdns/recursor.d/cloudimg-secrets.yml

the credentials file is 0600 root root, the base config restricts incoming allow_from to loopback and RFC1918 private ranges with no 0.0.0.0/0 so it is not an open resolver, and the per VM secrets drop-in is 0640 root pdns

Step 8: Allow your own clients to resolve

By default only loopback and RFC1918 ranges may query the resolver. To let a specific client subnet resolve, add it as a new list item under incoming.allow_from in the base config and reload. Never add 0.0.0.0/0 — that would make this an open resolver abusable for DNS amplification.

sudoedit /etc/powerdns/recursor.d/cloudimg-recursor.yml
# under the allow_from: list, add a line for your client subnet, for example:
#     - <your-mgmt-cidr>
sudo systemctl reload pdns-recursor

Then from a client inside that subnet, point its resolver at this VM's IP and test:

dig @<public-ip> A example.com +short

Step 9: DNSSEC validation

The Recursor validates DNSSEC signed zones. A query for a correctly signed name returns the ad (authenticated data) flag, while a deliberately broken signature fails to resolve — proof the resolver is protecting your clients from tampered answers.

dig @127.0.0.1 A cloudflare.com +dnssec +multiline | grep -E 'flags:|status:'
dig @127.0.0.1 A example.com +dnssec | grep -E 'flags:|status:'

Step 10: Forwarding and RPZ threat filtering

For split horizon or internal domains, forward specific zones to an internal authoritative server by adding a recursor.forward_zones entry (YAML). For DNS firewalling, load a Response Policy Zone (RPZ) so the resolver blocks known malicious domains. These are configured as YAML drop-ins in /etc/powerdns/recursor.d/; see the PowerDNS Recursor documentation for the full schema. Example forward zone drop-in:

recursor:
  forward_zones:
    - zone: internal.example
      forwarders:
        - 10.0.0.53

Step 11: Security recommendations

  • Keep the resolver closed to the internet. Only add the specific client subnets that need resolution to incoming.allow_from. Never add 0.0.0.0/0. The NSG should also allow UDP and TCP 53 only from those networks.

  • Keep the REST API on loopback. The image binds the API and status webserver to 127.0.0.1 and sets webservice.allow_from to loopback. Do not expose it directly; tunnel port 8082 over SSH if you need it remotely.

  • Enable RPZ (Step 10) to block malicious and unwanted domains at the resolver.

  • Restrict administration. Allow TCP 22 for administration only, from your management network.

  • Keep the OS and PowerDNS patched. Unattended security upgrades remain enabled on the running VM, including the official PowerDNS repository for the rec 53 branch.

  • Monitor cache and query rates. Use rec_control get-all or the REST API metrics to watch query volume, cache hit ratio and servfail rates.

Step 12: Support and Licensing

PowerDNS Recursor is developed by PowerDNS.COM BV and distributed under the GNU General Public License version 2 (GPL-2.0) with an OpenSSL linking exception (see the upstream NOTICE file). This cloudimg image bundles the unmodified official PowerDNS packages. cloudimg provides the packaging, the secure by default configuration, the per instance credential automation, and 24/7 support with a guaranteed 24 hour response SLA.

cloudimg is not affiliated with or endorsed by PowerDNS.COM BV. PowerDNS is a mark of its respective owner and is used here only to identify the software.

Deploy on Azure

Find PowerDNS Recursor on Ubuntu 24.04 LTS on the Azure Marketplace, published by cloudimg. Deploy from the Portal or the Azure CLI as shown above.

Need Help?

Email support@cloudimg.co.uk for deployment help, configuration questions, or licensing enquiries.