SkillAgentSearch skills...

Powerdns

PowerDNS dnsdist, recursor, authoritative, and admin interface. Supports DNSCrypt, DoH, and DoT.

Install / Use

/learn @chrisss404/Powerdns

README

Introduction

Get your own secure nameserver up and running within minutes, using this dockerized installation of the PowerDNS nameserver.

Source code of PowerDNS here: https://github.com/PowerDNS/pdns

Private Recursor

Simple example of an ad blocking private recursor that is listening for DNSCrypt and DNS-over-TLS (DoT) queries. Easy setup for any desktop OS using dnscrypt-proxy and Android 9 has native support for DoT.

Create private-recursor.yml like this:

services:

  gateway:
    image: jwilder/nginx-proxy:alpine
    volumes:
      - "/var/run/docker.sock:/tmp/docker.sock:ro"
      - "/etc/nginx/vhost.d"
      - "/usr/share/nginx/html"
      - "/etc/nginx/certs"
    ports:
      - "80:80"

  letsencrypt:
    image: jrcs/letsencrypt-nginx-proxy-companion:latest
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
    volumes_from:
      - gateway

  dnsdist:
    image: chrisss404/powerdns:latest-dnsdist
    environment:
      - VIRTUAL_HOST=dot.example.com
      - VIRTUAL_PORT=9999
      - LETSENCRYPT_EMAIL=you@example.com
      - LETSENCRYPT_HOST=dot.example.com
      - DNSDIST_DNSCRYPT=yes
      - DNSDIST_DNS_OVER_TLS=yes
      - DNSDIST_DNS_OVER_TLS_DOMAIN=dot.example.com
    volumes:
      - "./blocklist.txt:/etc/dnsdist/blocklist.txt:ro"
    volumes_from:
      - gateway:ro
    networks:
      - recursor
    ports:
      - "853:853/tcp"
      - "8443:8443/udp"
      - "8443:8443/tcp"

  recursor:
    image: chrisss404/powerdns:latest-recursor
    sysctls:
      - net.ipv6.route.max_size=16384
    networks:
      recursor:
        ipv4_address: 172.31.117.117

networks:
  recursor:
    ipam:
      driver: default
      config:
        - subnet: "172.31.117.0/24"

Create blocklist.txt like this:

googleadservices.com
...

Then you can do the following:

# start secure recursor (restart dnsdist after the let's encrypt certificate is created)
docker compose -f private-recursor.yml up

# get DNSCrypt provider public key fingerprint
docker compose -f private-recursor.yml exec dnsdist dnsdist -e 'printDNSCryptProviderFingerprint("/var/lib/dnsdist/providerPublic.key")'

# create DNS stamp using python dnsstamps library or visit https://dnscrypt.info/stamps
dnsstamp.py dnscrypt -s -a 1.2.3.4:8443 -n 2.dnscrypt-cert.example.com -k 2251:468C:FE4C:C39F:9DF3:C2BA:7C95:ED8F:94F6:06BC:7A24:0493:D168:DE9E:7682:E8AD

Connect using DNSCrypt Proxy

  • Install dnscrypt proxy as described here.
  • Configure dnscrypt proxy to use previously created dnsstamp, e.g.: vim /etc/dnscrypt-proxy/dnscrypt-proxy.toml
-server_names = ['cisco', 'cloudflare']
+server_names = ['example']

[static]
+  [static.'example']
+  stamp = 'sdns://AQEAAAAAAAAADDEuMi4zLjQ6ODQ0MyAiUUaM_kzDn53zwrp8le2PlPYGvHokBJPRaN6edoLorRsyLmRuc2NyeXB0LWNlcnQuZXhhbXBsZS5jb20'

Connect using Android

  • Go to Settings > Network & Internet > Advanced > Private DNS > Private DNS provider hostname
  • Enter DoT hostname: dot.example.com

<a href="https://raw.githubusercontent.com/chrisss404/powerdns/master/android-dot.png"><img src="https://raw.githubusercontent.com/chrisss404/powerdns/master/android-dot.png" height="200"/></a>

Private Authoritative Server

Simple example of full powerdns stack including private authoritative nameserver and admin interface for editing DNS records.

Create private-authoritative.yml like this:

services:

  admin:
    image: chrisss404/powerdns:latest-admin
    depends_on:
      - admin-db
      - authoritative
    environment:
      - ADMIN_PDNS_API_KEY=api-secret-authoritative
      - ADMIN_USER_PASSWORD=very-secret
    networks:
      - admin-db
      - authoritative
    ports:
      - "80:3031"

  admin-db:
    image: postgres:12.1-alpine
    environment:
      - POSTGRES_DB=pda
      - POSTGRES_INITDB_ARGS=--data-checksums
      - POSTGRES_PASSWORD=pda
      - POSTGRES_USER=pda
    networks:
      - admin-db

  authoritative:
    image: chrisss404/powerdns:latest-authoritative
    depends_on:
      - authoritative-db
    environment:
      - AUTHORITATIVE_API=yes
      - AUTHORITATIVE_API_KEY=api-secret-authoritative
      - AUTHORITATIVE_WEBSERVER=yes
      - AUTHORITATIVE_WEBSERVER_PASSWORD=web-secret-authoritative
    networks:
      authoritative:
        ipv4_address: 172.31.118.118
      authoritative-db:
    ports:
      - "8081:8081/tcp"

  authoritative-db:
    image: postgres:12.1-alpine
    environment:
      - POSTGRES_DB=pdns
      - POSTGRES_INITDB_ARGS=--data-checksums
      - POSTGRES_PASSWORD=pdns
      - POSTGRES_USER=pdns
    networks:
      - authoritative-db

  dnsdist:
    image: chrisss404/powerdns:latest-dnsdist
    environment:
      - DNSDIST_API_KEY=api-secret-dnsdist
      - DNSDIST_PLAIN=yes
      - DNSDIST_QUIET=no
      - DNSDIST_WEBSERVER=yes
      - DNSDIST_WEBSERVER_PASSWORD=web-secret-dnsdist
    networks:
      - recursor
    ports:
      - "1053:53/tcp"
      - "1053:53/udp"
      - "8083:8083/tcp"

  recursor:
    image: chrisss404/powerdns:latest-recursor
    environment:
      - RECURSOR_API_KEY=api-secret-recursor
      - RECURSOR_DNSSEC=validate
      - RECURSOR_FORWARD_ZONES={"zone":"sys","forwarders":["172.31.118.118"]}
      - RECURSOR_QUIET=false
      - RECURSOR_TRUST_ANCHORS=sys=54970 13 1 27efe1c1a790c3cbb43b947d6d6dfac62507097e
      - RECURSOR_WEBSERVER=true
      - RECURSOR_WEBSERVER_PASSWORD=web-secret-recursor
    sysctls:
      - net.ipv6.route.max_size=16384
    networks:
      recursor:
        ipv4_address: 172.31.117.117
      authoritative:
    ports:
      - "8082:8082/tcp"

networks:
  admin-db:
  authoritative:
    ipam:
      driver: default
      config:
        - subnet: "172.31.118.0/24"
  authoritative-db:
  recursor:
    ipam:
      driver: default
      config:
        - subnet: "172.31.117.0/24"

Then you can do the following:

# start powerdns stack
docker compose -f private-authoritative.yml up

# send DNS queries
dig -p 1053 example.com

# PowerDNS admin interface
http://localhost:80

# PowerDNS authoritative stats
http://localhost:8081

# PowerDNS recursor stats
http://localhost:8082

# PowerDNS dnsdist stats
http://localhost:8083

Settings

Admin

| Env-Variable | Description | | -------------------- | -------------------------------------------------------- | | ADMIN_DB_HOST | Postgres host (default: admin-db) | | ADMIN_DB_NAME | Postgres database (default: pda) | | ADMIN_DB_PASS | Postgres password (default: pda) | | ADMIN_DB_PORT | Postgres port (default: 5432) | | ADMIN_DB_USER | Postgres username (default: pda) | | ADMIN_PDNS_API_KEY | PowerDNS API key (default: pdns) | | ADMIN_PDNS_API_URL | PowerDNS API URL (default: http://authoritative:8081/) | | ADMIN_PDNS_VERSION | PowerDNS version number (default: 4.2.1) | | ADMIN_SIGNUP_ENABLED | Allow users to sign up (default: no) | | ADMIN_USER_EMAIL | Email address of admin user (default: admin@example.org) | | ADMIN_USER_FIRSTNAME | First name of admin user (default: Administrator) | | ADMIN_USER_LASTNAME | Last name of admin user (default: User) | | ADMIN_USER_PASSWORD | Password of admin user (default: admin) |

Authoritative

| Env-Variable | Description | |-------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------| | AUTHORITATIVE_ALLOW_AXFR_IPS | Allow zonetransfers only to these subnets (default: 127.0.0.0/8,::1) | | AUTHORITATIVE_ALLOW_NOTIFY_FROM | Allow AXFR NOTIFY from these IP ranges (default: 0.0.0.0/0,::/0) | | AUTHORITATIVE_API | Enable/disable the REST API (default: no) | | AUTHORITATIVE_API_KEY | Static pre-shared authentication key for access to the REST API (default: pdns) | | AUTHORITATIVE_DB_HOST | Postgres host (default: authoritative-db) | | AUTHORITATIVE_DB_NAME | Postgres database (default: pdns) | | AUTHORITATIVE_DB_PASS | Postgres password (default: pdns)

View on GitHub
GitHub Stars62
CategoryCustomer
Updated1mo ago
Forks21

Languages

Shell

Security Score

100/100

Audited on Feb 9, 2026

No findings