Skip to content
PowerDNS support for the apnscp control panel
Branch: master
Clone or download
Type Name Latest commit message Commit time
Failed to load latest commit information.
plays/powerdns-authoritative-setup Accept a variety of powerdns_recursive_ns formats. Transform to resol… Aug 15, 2019
src Deletion purges all alike records Sep 11, 2019
.gitignore Relocate module, cleanup gitignore EOL Jul 11, 2019 Update Changelog Jul 29, 2019
LICENSE Changes (#3) Aug 5, 2019 General fixes to record addition, creation and modification Jul 18, 2019
setup.yml addin task completed Jul 11, 2019

PowerDNS DNS Provider

This is a drop-in provider for apnscp to enable DNS support using PowerDNS. This module may use PostgreSQL or MySQL as a backend driver.

Nameserver installation

Local PowerDNS

Clone the repository into the Bootstrapper addin path. Note this requires either apnscp v3.1 or apnscp v3.0.47 minimum to work.

cd /usr/local/apnscp/resources/playbooks
git clone addins/apnscp-powerdns
ansible-playbook addin.yml --extra-vars=addin=apnscp-powerdns

PostgreSQL can be used by specifying powerdns_driver=pgsql, cpcmd config:set will accomplish this:

cpcmd config:set apnscp.bootstrapper powerdns_driver pgsql
ansible-playbook addin.yml --extra-vars=addin=apnscp-powerdns

PowerDNS is now setup to accept requests on port 8081. Requests require an authorization key that can be found in /etc/pdns/pdns.conf

# Install jq if not already installed
yum install -y jq
# This is your API key
grep '^api-key=' /etc/pdns/pdns.conf | cut -d= -f2
curl -v -H 'X-API-Key: APIKEYABOVE' | jq .

apnscp provides a DNS-only license class that allows apnscp to run on a server without the capability to host sites. These licenses are free and may be requested via Contact if these licenses are not available at time of writing for manual issuance.

Remote PowerDNS (alternate install)

Alternatively, apnscp can be configured to connect to a remote PowerDNS server. This is useful if running a DNS cluster and want every apnscp server to connect to it.

cd /usr/local/apnscp
git submodule add resources/playbooks/addins/apnscp-powerdns
ln -rs resources/playbooks/addins/apnscp-powerdns/src lib/Opcenter/Dns/Providers/Powerdns

Proced with the setup in section "apnscp DNS provider setup" below. The API key will be sourced from your remote server.

git submodule vs git clone usage

Astute observers will notice git clone used in the first example and git submodule in the above. Any submodule added to apnscp will automatically update with upcp. Any repository cloned via git clone is not updated with upcp. The choice is yours.

Idempotently changing configuration

PowerDNS may be configured via files in /etc/pdns/local.d. In addition to this location, Bootstrapper supports injecting settings via powerdns_custom_config. For example,

cpcmd config:set apnscp.bootstrapper 'powerdns_custom_config' '["allow-axfr-ips":,"also-notify":]'
cd /usr/local/apnscp/resources/playbooks
ansible-playbook addin.yml --extra-vars=addin=apnscp-powerdns

allow-axfr-ips and also-notify directives will be set whenever the addin plays are run.

Enabling ALIAS support

ALIAS is a synthetic record that allows CNAME records to be set on the zone apex. ALIAS records require powerdns_enable_recursion to be enabled as well as an optional powerdns_recursive_ns to be set otherwise it will default to the system in /etc/resolv.conf.

cpcmd config:set apnscp.bootstrapper powerdns_enable_recursion true
cpcmd config:set apnscp.bootstrapper powerdns_recursive_ns '[,]'
# Then re-run the addin...
cd /usr/local/apnscp/resources/playbooks
ansible-playbook addin.yml --extra-vars=addin=apnscp-powerdns

Remote API access

In the above example, only local requests may submit DNS modifications to the server. None of the below examples affect querying; DNS queries occur over 53/UDP typically (or 53/TCP if packet size exceeds UDP limits). Depending upon infrastructure, there are a few options to securely accept record submission, all of which require an API key for submission.

SSL + Apache

Apache's ProxyPass directive send requests to the backend. Brute-force attempts are protected by mod_evasive bundled with apnscp. Requests over this medium are protected by SSL, without HTTP/2 to ameliorate handshake overhead. In all but the very high volume API request environments, this will be acceptable.

In this situation, the endpoint is Changes are made to /etc/httpd/conf/httpd-custom.conf within the <VirtualHost ... :443> bracket (with SSLEngine On!). After adding the below changes, systemctl restart httpd.

<Location /dns>

Downsides: minor SSL overhead. Dependent upon Apache.
Upsides: easy to setup. Protected by threat deterrence. PowerDNS accessible remotely via an easily controlled URI.

In the above example, API requests can be made via, e.g.

curl -q -H 'X-API-Key: SOMEKEY' 

Disabling brute-force throttling

As hinted above, placing PowerDNS behind Apache confers brute-force protection by mod_evasive. By default, 10 of the same requests in 2 seconds can trigger a brute-force block. Two solutions exist, either raise the same-page request threshold or disable mod_evasive.

Working off the example above <Location /dns> ...

<Location /dns>
	# Raise threshold to 30 same-page requests in 2 seconds
	DOSPageCount 30
	DOSPageInterval 2

	# Or disable entirely
	DOSEnabled off

Standalone server

PowerDNS can also run by itself on a different port. In this situation, the network is configured to block all external requests to port 8081 except those whitelisted. For example, if the entire network can be trusted and under your control, then whitelist the IP range:

cpcmd rampart:whitelist

Additionally, PowerDNS' whitelist must be updated as well. This can be quickly accomplished using the apnscp.bootstrapper Scope:

cpcmd config:set apnscp.bootstrapper powerdns_localonly false
cd /usr/local/apnscp/resources/playbooks
ansible-playbook addin.yml --extra-vars=addin=apnscp-powerdns

Downsides: requires whitelisting IP addresses for access to API server. Must run on port different than Apache.
Upsides: operates independently from Apache.

The server may be accessed once the source IP has been whitelisted,

curl -q -H 'X-API-Key: SOMEKEY' 

apnscp DNS provider setup

Every server that runs apnscp may delegate DNS authority to PowerDNS. This is ideal in distributed infrastructures in which coordination allows for seamless server-to-server migrations.

Taking the API key from above and using the SSL + Apache approach above, let's configure /usr/local/apnscp/config/auth.yaml. Configuration within this file is secret and is not exposed via apnscp's API. Once set restart apnscp to compile configuration, systemctl restart apnscp.

  # This url may be different if using running PowerDNS in standalone
  key: your_api_key_here
  recursion: false
    ## Optional additional nameservers
  • uri value is the hostname of your master PowerDNS server running the HTTP API webserver (without a trailing slash)
  • key value is the API Key in pdns.conf on the master nameserver.
  • ns value is a list of nameservers as in the example above. Put nameservers on their own lines prefixed with a hyphen and indented accordingly. There is not currently a limit for the number of nameservers you may use, 2-5 is typical and should be geographically distributed per RFC 2182.
  • recursion controls ALIAS records, which are CNAMEs on apex (RFC 1034). Enabling requires configuration of resolver and expand-alias in pdns.conf.

Setting as default

PowerDNS may be configured as the default provider for all sites using the dns.default-provider Scope. When adding a site in Nexus or AddDomain the key will be replaced with "DEFAULT". This is substituted automatically on account creation.

cpcmd config:set dns.default-provider powerdns

Do not set dns.default-provider-key. API key is configured via config/auth.yaml.


  • Module- overrides Dns_Module behavior
  • Validator- service validator, checks input with AddDomain/EditDomain helpers

Minimal module methods

All module methods can be overwritten. The following are the bare minimum that are overwritten for this DNS provider to work:

  • atomicUpdate() attempts a record modification, which must retain the original record if it fails
  • zoneAxfr() returns all DNS records
  • add_record() add a DNS record
  • remove_record() removes a DNS record
  • get_hosting_nameservers() returns nameservers for the DNS provider
  • add_zone_backend() creates DNS zone
  • remove_zone_backend() removes a DNS zone

See also: Creating a provider (


Submit a PR and have fun!

You can’t perform that action at this time.