dnsdist is a highly performant, flexible DNS load balancer and packet cache developed by the PowerDNS team. It sits between DNS clients and backend DNS servers, providing advanced traffic management, security features, and protocol support.
⚠️ Version Note: dnsdist 2.1.0-alpha1 introduces breaking changes including YAML configuration as default (
dnsdist.yml), OpenTelemetry support, and structured logging. The h2o library support for DoH has been removed (nghttp2 only). Test existing configurations before upgrading.
dnsdist operates as a reverse proxy for DNS traffic:
Clients → dnsdist → Backend DNS Servers
↓
(Load Balancing, Filtering, Caching, DoT/DoH)
┌─────────────┐
Clients ───────►│ dnsdist │
(DNS/DoT/DoH) │ :853/:443 │
└──────┬──────┘
│
┌─────────────────┼─────────────────┐
│ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│ Backend │ │ Backend │ │ Backend │
│ DNS │ │ DNS │ │ DNS │
│ :53 │ │ :53 │ │ :53 │
└─────────┘ └─────────┘ └─────────┘
-- Define backend servers
newServer{address="192.168.1.10:53", pool="auth"}
newServer{address="192.168.1.11:53", pool="auth"}
newServer{address="192.168.1.12:53", pool="auth"}
-- Set load balancing policy
setServerPolicy(roundrobin)
-- Listen on standard DNS port
addLocal("0.0.0.0:53")
addLocal(":::53")
-- Web interface for statistics
webserver("0.0.0.0:8083", "web_password")
-- DoT listener
addTLSLocal("0.0.0.0:853", "/etc/dnsdist/dnsdist.crt", "/etc/dnsdist/dnsdist.key")
-- Backend servers
newServer{address="192.168.1.10:53"}
newServer{address="192.168.1.11:53"}
-- DoH listener
addDOHLocal("0.0.0.0:443", "/etc/dnsdist/dnsdist.crt", "/etc/dnsdist/dnsdist.key", "/dns-query")
-- Backend servers
newServer{address="192.168.1.10:53"}
newServer{address="192.168.1.11:53"}
-- Rate limit queries from single IP
addAction(
MaxQPSIPRule(50, 100), -- 50 qps sustained, 100 burst
DropAction()
)
-- Rate limit specific query types
addAction(
AndRule({QTypeRule("ANY"), MaxQPSRule(10)}),
DropAction()
)
-- Block queries for known malware domains
addAction(
SuffixRule("malware-domain.com"),
DropAction()
)
-- Block ANY queries (amplification attack vector)
addAction(
QTypeRule("ANY"),
DropAction()
)
-- Redirect specific queries
addAction(
SuffixRule("internal.example.com"),
PoolAction("internal")
)
-- Backend with health checks
newServer{
address="192.168.1.10:53",
checkInterval=10,
checkTimeout=2,
setCD=true
}
-- Enable packet cache
setPacketCacheSize(10000)
-- Configure cache behavior
setECSServFailTTL(60)
setServFailTTL(60)
setTempFailureTTL(60)
# Install from distribution repositories (may be older version)
sudo apt update
sudo apt install dnsdist
# For latest version, add PowerDNS repository
curl -fsSL https://repo.powerdns.com/FD380FBB-pub.asc | sudo tee /etc/apt/keyrings/pdns-archive-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/pdns-archive-keyring.gpg] https://repo.powerdns.com/ubuntu $(lsb_release -cs)-dnsdist-20 main" | sudo tee /etc/apt/sources.list.d/powerdns.list
# Install latest dnsdist
sudo apt update
sudo apt install dnsdist
# Enable EPEL repository
sudo dnf install -y epel-release
# Install from EPEL (may be older version)
sudo dnf install dnsdist
# For latest version, add PowerDNS repository
curl -fsSL https://repo.powerdns.com/repo-files/el-dnsdist-20.repo | sudo tee /etc/yum.repos.d/powerdns-dnsdist.repo
# Install latest dnsdist
sudo dnf install dnsdist
# Install dependencies (Debian/Ubuntu)
sudo apt install build-essential autoconf automake libtool \
libboost-all-dev liblua5.1-dev libedit-dev \
libssl-dev libsodium-dev libnghttp2-dev
# Clone repository
git clone https://github.com/PowerDNS/pdns.git
cd pdns/pdns/dnsdistdist
# Build
autoreconf -i
./configure
make
# Install
sudo make install
Note: For detailed build instructions and dependencies, see the official documentation.
⚠️ Production Note: Official Docker images are available at
powerdns/dnsdist-20. Mount persistent volumes for configuration and certificates. See Docker Deployment Guide for complete examples.
Version 2.0.x:
version: '3.8'
services:
dnsdist:
image: powerdns/dnsdist-20:2.0.2
container_name: dnsdist
restart: unless-stopped
ports:
- "53:53/udp"
- "53:53/tcp"
- "853:853/tcp" # DoT
- "443:443/tcp" # DoH
- "8083:8083/tcp" # Web interface
volumes:
- ./config:/etc/dnsdist:ro
- ./certs:/etc/dnsdist/certs:ro
cap_add:
- NET_BIND_SERVICE
networks:
- dns-net
networks:
dns-net:
driver: bridge
Note: For production use, mount persistent volumes for
/etc/dnsdist(configuration) and/etc/dnsdist/certs(TLS certificates). See Docker Deployment Guide for complete examples.
# Start/stop/restart
sudo systemctl start dnsdist
sudo systemctl stop dnsdist
sudo systemctl restart dnsdist
# Check status
sudo systemctl status dnsdist
# View logs
sudo journalctl -u dnsdist -f
# Connect to console
sudo dnsdist
Access statistics at http://localhost:8083/
-- Enable Prometheus endpoint
webserver("0.0.0.0:8083", "password")
-- Access metrics at /metrics
-- Primary pool
newServer{address="192.168.1.10:53", pool="primary"}
newServer{address="192.168.1.11:53", pool="primary"}
-- Backup pool
newServer{address="192.168.1.20:53", pool="backup"}
-- Use primary, failover to backup
setServerPolicy(firstAvailable)
-- European backends
newServer{address="192.168.1.10:53", pool="eu", latency=10}
newServer{address="192.168.1.11:53", pool="eu", latency=15}
-- US backends
newServer{address="192.168.2.10:53", pool="us", latency=50}
newServer{address="192.168.2.11:53", pool="us", latency=55}
-- Route based on latency
setServerPolicy(latencyOrder)
-- Global rate limit
addAction(AllRule(), MaxQPSRule(10000))
-- Per-IP rate limit
addAction(AllRule(), MaxQPSIPRule(50, 100))
-- Block amplification vectors
addAction(QTypeRule("ANY"), DropAction())
addAction(QTypeRule("TXT"), MaxQPSRule(100))
-- Internal queries
addAction(
NetGroupRule({"10.0.0.0/8", "192.168.0.0/16"}),
PoolAction("internal")
)
-- External queries
addAction(
AllRule(),
PoolAction("external")
)
-- Define pools
newServer{address="10.0.1.10:53", pool="internal"}
newServer{address="203.0.113.10:53", pool="external"}
-- PowerDNS Authoritative backends
newServer{address="192.168.1.10:53", pool="auth"}
newServer{address="192.168.1.11:53", pool="auth"}
-- Recursive resolver for external queries
newServer{address="192.168.1.20:53", pool="recursor"}
-- Route internal queries to authoritative
addAction(
SuffixRule("internal.example.com"),
PoolAction("auth")
)
-- Route external queries to recursor
addAction(
AllRule(),
PoolAction("recursor")
)
-- BIND servers as backends
newServer{address="192.168.1.10:53"}
newServer{address="192.168.1.11:53"}
-- dnsdist provides DoT/DoH frontend
addTLSLocal("0.0.0.0:853", "/etc/dnsdist/dnsdist.crt", "/etc/dnsdist/dnsdist.key")
-- Knot DNS authoritative servers
newServer{address="192.168.1.10:53"}
newServer{address="192.168.1.11:53"}
-- Load balance across Knot instances
setServerPolicy(roundrobin)
-- Restrict web interface access
webserver("127.0.0.1:8083", "strong_password")
setACL({"127.0.0.0/8", "::1/128"})
-- Use strong TLS configuration
setTLSConfig({
ciphers = "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384",
ciphers13 = "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256",
minTLSVersion = "TLSv1.2"
})
-- Increase worker threads
setWorkerThreads(4)
-- Tune cache size
setPacketCacheSize(100000)
-- Adjust TCP settings
setTCPRecvTimeout(2)
setTCPSendTimeout(2)
setMaxTCPClientThreads(10)
Backend not responding:
-- Check backend status in console
showServers()
High latency:
-- View latency statistics
showServers()
Rate limiting too aggressive:
-- Adjust rate limits
-- Modify MaxQPSRule values
# Connect to console
sudo dnsdist
# Show server status
showServers()
# Show statistics
showStats()
# Show rules
showRules()
# Show dynamic blocks
showDynamicBlocks()
Questions? Find all contact information on our contact page.