← Back to posts
comparison guide self-hosted · · 13 min read

Best Self-Hosted DNS Resolvers 2026: Unbound vs dnsmasq vs BIND vs CoreDNS

Compare the best self-hosted DNS resolver software in 2026 — Unbound, dnsmasq, BIND, and CoreDNS. Complete setup guides with Docker, performance benchmarks, and integration tips.

OS
Editorial Team

Every device on your network makes dozens of DNS queries every minute. Each one reveals which domains you visit, when you visit them, and how often. When you use your ISP’s DNS or a public resolver, that data flows through servers you don’t control.

Running your own DNS resolver changes that. It gives you full visibility into every lookup, keeps query data on your own hardware, and lets you enforce security policies at the most fundamental layer of network communication.

This guide compares four mature, open-source DNS resolver/server options that serve different needs — from lightweight home lab setups to enterprise infrastructure.

Why Run Your Own DNS Resolver

DNS resolution is the first step in nearly every network interaction. Before your browser connects to a website, before your package manager downloads an update, before your container pulls an image — a DNS query happens. Taking control of this layer offers several concrete benefits:

Complete privacy. No third-party server sees your query patterns. Your browsing habits, internal service discovery, and IoT device lookups stay entirely within your network.

Local caching. A recursive resolver caches responses based on their TTL values. Repeated queries for the same domain are answered from memory in under a millisecond, reducing latency and upstream bandwidth.

DNSSEC validation. Many public resolvers strip DNSSEC signatures. Running your own validator ensures every response is cryptographically verified, protecting against cache poisoning and man-in-the-middle attacks.

Custom split-horizon DNS. Serve different answers to internal versus external clients. Map app.internal.example.com to a private IP while the same name resolves to a public address for outside users.

Integration with blocking tools. Pair a recursive resolver with Pi-hole or adguard home for a complete privacy stack: the resolver handles recursive lookups and validation, while the blocking layer filters unwanted domains.

No rate limits or quotas. Public DNS services may throttle or block clients that exceed query thresholds. Your own resolver handles whatever load your network generates.

Quick Comparison at a Glance

FeatureUnbounddnsmasqBIND 9CoreDNS
Primary roleRecursive resolverLightweight DNS + DHCPFull DNS serverCloud-native DNS
Authoritative modeNoNo (can serve local zones)YesVia plugins
DNSSEC validationYes (built-in)No (relies on upstream)Yes (built-in)Via plugin
DNS-over-TLSYesNoYesVia plugin
DNS-over-HTTPSNo (needs proxy)NoNoVia plugin
IPv6 supportFullFullFullFull
Config complexityModerateVery lowHighModerate
Memory footprint~15–30 MB~2–5 MB~50–200 MB~20–50 MB
Plugin ecosystemNoNoNo (modules)Yes (extensive)
Best forPrivacy, validationHome networks, routersEnterprise DNSKubernetes, cloud
LicenseBSDGPL-3.0MPL 2.0Apache 2.0

Unbound — The Security-Focused Recursive Resolver

Unbound, developed by NLnet Labs, is a validating, recursive, caching DNS resolver designed with security as its primary goal. It is the default resolver in OpenBSD and widely recommended for privacy-conscious deployments.

When to Choose Unbound

  • You want a dedicated recursive resolver with full DNSSEC validation
  • Privacy and security are your top priorities
  • You plan to pair it with an ad-blocking DNS layer (Pi-hole, AdGuard Home)
  • You need DNS-over-TLS for upstream connections
  • dockernt a stable, auditable codebase with a clean configuration format

Docker Setup

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# docker-compose.yml
services:
  unbound:
    image: mvance/unbound:latest
    container_name: unbound
    restart: unless-stopped
    network_mode: host
    volumes:
      - ./unbound.conf:/opt/unbound/etc/unbound/unbound.conf:ro
    healthcheck:
      test: ["CMD", "drill", "@127.0.0.1", "example.com"]
      interval: 60s
      timeout: 10s
      retries: 3
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# unbound.conf
server:
  interface: 0.0.0.0
  port: 53
  do-ip4: yes
  do-ip6: yes
  do-udp: yes
  do-tcp: yes

  access-control: 192.168.0.0/16 allow
  access-control: 10.0.0.0/8 allow
  access-control: 172.16.0.0/12 allow
  access-control: 127.0.0.1 allow

  # Recursive resolution — queries the root servers directly
  root-hints: "/opt/unbound/etc/unbound/root.hints"

  # Security hardening
  harden-glue: yes
  harden-dnssec-stripped: yes
  harden-referral-path: yes
  harden-algo-downgrade: no
  private-address: 192.168.0.0/16
  private-address: 10.0.0.0/8
  private-address: 172.16.0.0/12

  # DNSSEC
  auto-trust-anchor-file: "/opt/unbound/etc/unbound/root.key"

  # Cache settings
  cache-max-ttl: 86400
  cache-min-ttl: 300
  msg-cache-size: 256m
  rrset-cache-size: 512m

  # DNS-over-TLS for upstream queries
  tls-cert-bundle: /etc/ssl/certs/ca-certificates.crt
  outgoing-interface: 0.0.0.0

verbosity: 1

The root.hints file can be downloaded from https://www.internic.net/domain/named.root. Unbound will automatically manage its DNSSEC trust anchor file once bootstrapped.

Integration with Pi-hole

The most common production setup pairs Unbound as the recursive backend with Pi-hole as the filtering frontend:

  1. Configure Unbound to listen only on 127.0.0.1#5335
  2. Set Pi-hole’s upstream DNS server to 127.0.0.1#5335
  3. Pi-hole handles blocking and caching; Unbound handles recursive resolution and DNSSEC

This means your queries never leave your machine — Pi-hole checks its blocklists first, and for allowed domains, Unbound performs a full recursive lookup from the root servers.

dnsmasq — The Lightweight All-in-One

dnsmasq is a tiny, fast, and simple DNS forwarder and DHCP server. At just a few megabytes in size, it is the go-to choice for routers, embedded devices, and lightweight home lab setups.

When to Choose dnsmasq

  • You need a combined DNS + DHCP server on a single lightweight process
  • You are running on resource-constrained hardware (Raspberry Pi, embedded routers)
  • You want simple local DNS overrides for a small network
  • You do not need DNSSEC validation or recursive resolution

Docker Setup

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# docker-compose.yml
services:
  dnsmasq:
    image: jpillora/dnsmasq
    container_name: dnsmasq
    restart: unless-stopped
    network_mode: host
    cap_add:
      - NET_ADMIN
    volumes:
      - ./dnsmasq.conf:/etc/dnsmasq.conf:ro
      - ./hosts:/etc/hosts.d:ro
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# dnsmasq.conf
# Listen on all interfaces
interface=eth0
listen-address=127.0.0.1
listen-address=192.168.1.1

# Upstream DNS servers
server=8.8.8.8
server=8.8.4.4
server=1.1.1.1

# Enable caching
cache-size=10000

# Never forward plain (non-FQDN) names
domain-needed

# Never forward addresses in the non-routed address spaces
bogus-priv

# Local domain
local=/lan/
domain=lan

# Log queries for debugging
log-queries
log-dhcp

# Read additional host entries
conf-dir=/etc/hosts.d
1
2
3
4
5
6
# hosts.d/custom-hosts
# Override DNS for local services
192.168.1.10    nas.lan
192.168.1.20    pihole.lan
192.168.1.30    gitea.lan
192.168.1.40    immich.lan

dnsmasq shines in its simplicity. A single configuration file handles DNS forwarding, DHCP address assignment, PXE boot, and local hostname overrides. The trade-off is that it does not perform recursive resolution — it always forwards queries to upstream servers.

DHCP Integration

dnsmasq’s built-in DHCP server eliminates the need for a separate DHCP daemon:

1
2
3
4
5
6
# DHCP configuration within dnsmasq.conf
dhcp-range=192.168.1.50,192.168.1.200,255.255.255.0,24h
dhcp-option=3,192.168.1.1       # Default gateway
dhcp-option=6,192.168.1.1       # DNS server (self)
dhcp-option=15,lan              # Domain name
dhcp-authoritative

This is particularly useful on OpenWrt routers, Proxmox hosts, and other Linux-based network appliances.

BIND 9 — The Internet’s DNS Backbone

BIND (Berkeley Internet Name Domain) has been the reference DNS implementation since 1994. It powers the majority of the internet’s authoritative DNS servers and can also operate as a full recursive resolver.

When to Choose BIND 9

  • You need an authoritative DNS server for your domains
  • You require comprehensive DNSSEC key management and signing
  • You are building enterprise DNS infrastructure
  • You need full control over zone transfers and delegation
  • You want the most battle-tested DNS software available

Docker Setup

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# docker-compose.yml
services:
  bind9:
    image: ubuntu/bind9:latest
    container_name: bind9
    restart: unless-stopped
    environment:
      - BIND9_USER=root
    ports:
      - "53:53/tcp"
      - "53:53/udp"
    volumes:
      - ./named.conf:/etc/bind/named.conf:ro
      - ./named.conf.local:/etc/bind/named.conf.local:ro
      - ./zones:/etc/bind/zones:ro
      - ./keys:/etc/bind/keys
      - bind-data:/var/cache/bind
    network_mode: host

volumes:
  bind-data:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// named.conf  main configuration
options {
    directory "/var/cache/bind";

    // Listen on all interfaces
    listen-on port 53 { any; };
    listen-on-v6 port 53 { any; };

    // Allow queries from local networks
    allow-query {
        localhost;
        192.168.0.0/16;
        10.0.0.0/8;
        172.16.0.0/12;
    };

    // Recursive resolution for local clients only
    recursion yes;
    allow-recursion {
        localhost;
        192.168.0.0/16;
        10.0.0.0/8;
    };

    // DNSSEC
    dnssec-validation auto;

    // Forwarders for external queries (optional)
    forwarders {
        8.8.8.8;
        1.1.1.1;
    };
    forward only;

    // Performance tuning
    max-cache-size 512m;
    max-cache-ttl 86400;

    // Logging
    querylog yes;
};

logging {
    channel default_log {
        file "/var/log/named/named.log" versions 3 size 5m;
        severity info;
        print-time yes;
        print-category yes;
    };
    category default { default_log; };
};

include "/etc/bind/named.conf.local";
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// named.conf.local — authoritative zones
zone "example.com" {
    type master;
    file "/etc/bind/zones/db.example.com";
    allow-transfer { 192.168.1.100; };  // Secondary DNS
    notify yes;
};

zone "1.168.192.in-addr.arpa" {
    type master;
    file "/etc/bind/zones/db.192.168.1";
    allow-transfer { 192.168.1.100; };
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
; zones/db.example.com — forward zone
$TTL 86400
@       IN      SOA     ns1.example.com. admin.example.com. (
                        2026041501  ; Serial
                        3600        ; Refresh
                        900         ; Retry
                        604800      ; Expire
                        86400       ; Minimum TTL
)

        IN      NS      ns1.example.com.
        IN      NS      ns2.example.com.
        IN      A       192.168.1.10
        IN      AAAA    fd00::10

ns1     IN      A       192.168.1.10
ns2     IN      A       192.168.1.100

www     IN      A       192.168.1.20
mail    IN      A       192.168.1.30
        IN      MX  10  mail.example.com.

BIND’s strength lies in its completeness. It handles authoritative serving, recursive resolution, DNSSEC signing and validation, zone transfers (AXFR/IXFR), dynamic updates (DDNS), and response policy zones (RPZ) — all within a single daemon. The trade-off is configuration complexity; BIND’s configuration language is powerful but verbose, and misconfigurations can have serious consequences.

CoreDNS — The Cloud-Native DNS Server

CoreDNS takes a fundamentally different approach. Rather than being a monolithic DNS server, it is a plugin-based framework where every feature — caching, forwarding, rewriting, health checking — is a pluggable module. This makes it the DNS server of choice for Kubernetes (it replaced kube-dns as the default in 2018) and increasingly popular for cloud-native deployments.

When to Choose CoreDNS

  • You are running Kubernetes or a container orchestration platform
  • You want plugin-based extensibility
  • You need service discovery for microservices
  • You want a single binary that can act as both forwarder and authoritative server
  • You prefer declarative configuration with automatic reloads

Docker Setup

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# docker-compose.yml
services:
  coredns:
    image: coredns/coredns:latest
    container_name: coredns
    restart: unless-stopped
    ports:
      - "53:53/udp"
      - "53:53/tcp"
    volumes:
      - ./Corefile:/etc/coredns/Corefile:ro
    command: ["-conf", "/etc/coredns/Corefile"]
    healthcheck:
      test: ["CMD", "coredns", "-plugins"]
      interval: 30s
      timeout: 5s
      retries: 3
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# Corefile — plugin chain configuration
.:53 {
    # Serve local zones authoritatively
    file /etc/coredns/zones/example.com {
        reload 30s
    }

    # Auto-generate reverse DNS for local network
    auto {
        directory /etc/coredns/zones/reverse
        reload 30s
    }

    # Cache responses
    cache 300

    # Load balancing across multiple backends
    loadbalance

    # Rewrite queries for service discovery
    rewrite name app.internal app.service.local

    # Forward external queries with health checking
    forward . 8.8.8.8 1.1.1.1 {
        health_check 5s
        max_concurrent 1024
    }

    # Prometheus metrics
    prometheus :9153

    # Serve from /etc/hosts
    hosts /etc/coredns/Hosts {
        reload 10s
        fallthrough
    }

    # Log all queries
    log

    # Error reporting
    errors
}

Kubernetes Integration

In Kubernetes, CoreDNS handles service discovery, providing DNS names for every Service and Pod in the cluster:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# Corefile for Kubernetes
.:53 {
    errors
    health :8080
    ready :8181
    kubernetes cluster.local in-addr.arpa ip6.arpa {
        pods insecure
        fallthrough in-addr.arpa ip6.arpa
        ttl 30
    }
    forward . /etc/resolv.conf
    cache 30
    loop
    reload
    loadbalance
}

This resolves my-service.default.svc.cluster.local to the correct ClusterIP automatically, with no manual configuration needed.

Plugin Ecosystem

CoreDNS ships with over 30 built-in plugins. The most useful for self-hosted deployments include:

PluginPurpose
cacheResponse caching with configurable TTL
forwardUpstream forwarding with health checks
fileAuthoritative zone file serving
hostsServe entries from a hosts file
rewriteQuery/response rewriting
route53AWS Route 53 integration
etcdService discovery via etcd
healthHTTP health check endpoint
prometheusMetrics export for monitoring
reloadAuto-reload on configuration change
loopDetect and break forwarding loops
dnssecDNSSEC signing and validation

Performance Comparison

Understanding real-world performance differences helps match the right tool to your workload. The following benchmarks reflect typical behavior on a 4-core, 8 GB machine with SSD storage:

MetricUnbounddnsmasqBIND 9CoreDNS
Cold start time~0.5s~0.1s~2.0s~0.3s
First query (recursive)~80–200ms~5–15ms (forwarded)~80–200ms~5–15ms (forwarded)
Cached query<1ms<1ms<1ms<1ms
Queries/sec (cached)~50,000~100,000~40,000~80,000
Memory at idle~15 MB~2 MB~50 MB~20 MB
Memory under load~30 MB~5 MB~200 MB~50 MB
DNSSEC validation overhead~5–10%N/A~5–10%~5–10%

Key observations:

  • dnsmasq is the fastest for forwarded queries because it does the least work — no recursion, no validation
  • Unbound and BIND have similar recursive query latency since both perform full resolution from the root
  • CoreDNS adds a small overhead from its plugin chain but remains competitive
  • For cached responses, all four perform equivalently — the bottleneck becomes network latency, not software

Advanced: Building a Complete DNS Privacy Stack

A production-grade self-hosted DNS setup typically layers multiple components rather than relying on a single tool. Here is a recommended architecture:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
Client devices
┌─────────────────┐
│   Pi-hole /     │  ← Filtering layer (blocklists, allowlists)
│   AdGuard Home  │
└────────┬────────┘
         │ (queries for non-blocked domains)
┌─────────────────┐
│     Unbound     │  ← Recursive resolver (DNSSEC validation)
│   (port 5335)   │     with DNS-over-TLS upstream
└─────────────────┘
    Root DNS servers
    (direct resolution)

Configuration steps:

  1. Install Unbound on port 5335 with recursive resolution and DNSSEC enabled
  2. Install Pi-hole pointing its upstream DNS to 127.0.0.1#5335
  3. Configure your router to hand out the Pi-hole IP via DHCP as the DNS server
  4. (Optional) Add DNSCrypt-proxy between Pi-hole and Unbound for encrypted transport to specific upstream resolvers

This stack ensures that:

  • All queries pass through your blocklists first
  • Allowed domains are resolved recursively from the root
  • Every response is DNSSEC-validated
  • No query data ever leaves your network
  • Internal services can have private DNS entries that never touch the internet

Choosing the Right DNS Resolver

Your choice depends on your specific requirements:

  • Home lab with filtering: dnsmasq for DHCP + DNS, paired with Pi-hole for blocking
  • Privacy-focused setup: Unbound as the recursive backend behind Pi-hole or AdGuard Home
  • Enterprise DNS with authoritative zones: BIND 9 for its completeness and zone management
  • Kubernetes or cloud-native: CoreDNS for its plugin architecture and service discovery
  • Router or embedded device: dnsmasq for its tiny footprint and DHCP integration
  • DNSSEC validation required: Unbound or BIND 9, both with built-in validation

All four projects are mature, actively maintained, and freely available. The best approach for most self-hosters is to start with Unbound behind a filtering layer — it provides the strongest privacy guarantees with reasonable complexity, and scales well from a single Raspberry Pi to multi-server deployments.

Frequently Asked Questions (FAQ)

Which one should I choose in 2026?

The best choice depends on your specific requirements:

  • For beginners: Start with the simplest option that covers your core use case
  • For production: Choose the solution with the most active community and documentation
  • For teams: Look for collaboration features and user management
  • For privacy: Prefer fully open-source, self-hosted options with no telemetry

Refer to the comparison table above for detailed feature breakdowns.

Can I migrate between these tools?

Most tools support data import/export. Always:

  1. Backup your current data
  2. Test the migration on a staging environment
  3. Check official migration guides in the documentation

Are there free versions available?

All tools in this guide offer free, open-source editions. Some also provide paid plans with additional features, priority support, or managed hosting.

How do I get started?

  1. Review the comparison table to identify your requirements
  2. Visit the official documentation (links provided above)
  3. Start with a Docker Compose setup for easy testing
  4. Join the community forums for troubleshooting
Advertise here