The CryptoLab Blog

Set Up Pi-hole As Truly Self-Contained DNS Resolver

The full article can be found here – https://github.com/anudeepND/pihole-unbound

Learn more about what a DNS recursive resolver is https://www.cloudflare.com/learning/dns/dns-server-types/

Setting up Pi-hole as a recursive DNS server solution

We will use unbound, a secure open source recursive DNS server primarily developed by NLnet Labs, VeriSign Inc., Nominet, and Kirei. The first thing you need to do is to install the recursive DNS resolver:

sudo apt install unbound

Optional: Download the list of primary root servers (serving the domain .). Unbound ships its own list, but we can also download the most recent list and update it whenever we think it is a good idea. Note: there is no point in doing it more often then every 6 months.

wget -O root.hints https://www.internic.net/domain/named.root
sudo mv root.hints /var/lib/unbound/

Configure unbound

Highlights:

  • Listen only for queries from the local Pi-hole installation (on port 5335)
  • Listen for both UDP and TCP requests
  • Verify DNSSEC signatures, discarding BOGUS domains
  • Apply a few security and privacy tricks

/etc/unbound/unbound.conf.d/pi-hole.conf

Run

sudo nano pi-hole.conf 

and copy the below information into that file

server:
    verbosity: 0
    
    interface: 127.0.0.1
    port: 5335
    do-ip4: yes
    do-udp: yes
    do-tcp: yes
    
    # May be set to yes if you have IPv6 connectivity
    do-ip6: no

    # You want to leave this to no unless you have *native* IPv6. With 6to4 and
    # Terredo tunnels your web browser should favor IPv4 for the same reasons
    prefer-ip6: no
    
    # Use this only when you downloaded the list of primary root servers!
    # Location of root.hints
    root-hints: "/var/lib/unbound/root.hints"
    
    # Trust glue only if it is within the servers authority
    harden-glue: yes
    
    # Ignore very large queries.
    harden-large-queries: yes
    
    # Require DNSSEC data for trust-anchored zones, if such data is absent, the zone becomes BOGUS
    # If you want to disable DNSSEC, set harden-dnssec stripped: no
    harden-dnssec-stripped: yes
    
    # Reduce EDNS reassembly buffer size.
    # Suggested by the unbound man page to reduce fragmentation reassembly problems
    edns-buffer-size: 1472
    
    # Rotates RRSet order in response (the pseudo-random 
    # number is taken from Ensure privacy of local IP 
    # ranges the query ID, for speed and thread safety).  
    # private-address: 192.168.0.0/16
    rrset-roundrobin: yes
    
    # Time to live minimum for RRsets and messages in the cache. If the minimum
    # kicks in, the data is cached for longer than the domain owner intended,
    # and thus less queries are made to look up the data. Zero makes sure the
    # data in the cache is as the domain owner intended, higher values,
    # especially more than an hour or so, can lead to trouble as the data in
    # the cache does not match up with the actual data anymore
    cache-min-ttl: 300
    cache-max-ttl: 86400
    
    # Have unbound attempt to serve old responses from cache with a TTL of 0 in
    # the response without waiting for the actual resolution to finish. The
    # actual resolution answer ends up in the cache later on. 
    serve-expired: yes
    
    # Harden against algorithm downgrade when multiple algorithms are
    # advertised in the DS record.
    harden-algo-downgrade: yes
    
    # Ignore very small EDNS buffer sizes from queries.
    harden-short-bufsize: yes
    
    # Refuse id.server and hostname.bind queries
    hide-identity: yes
    
    # Report this identity rather than the hostname of the server.
    identity: "Server"
    
    # Refuse version.server and version.bind queries
    hide-version: yes
    
    # Prevent the unbound server from forking into the background as a daemon
    do-daemonize: no
    
    # Number  of  bytes size of the aggressive negative cache.
    neg-cache-size: 4M
    
    # Send minimum amount of information to upstream servers to enhance privacy
    qname-minimisation: yes
    
    # Deny queries of type ANY with an empty response.
    # Works only on version 1.8 and above
    deny-any: yes

    # Do no insert authority/additional sections into response messages when
    # those sections are not required. This reduces response size
    # significantly, and may avoid TCP fallback for some responses. This may
    # cause a slight speedup
    minimal-responses: yes
    
    # Perform prefetching of close to expired message cache entries
    # This only applies to domains that have been frequently queried
    # This flag updates the cached domains
    prefetch: yes
    
    # Fetch the DNSKEYs earlier in the validation process, when a DS record is
    # encountered. This lowers the latency of requests at the expense of little
    # more CPU usage.
    prefetch-key: yes
    
    # One thread should be sufficient, can be increased on beefy machines. In reality for 
    # most users running on small networks or on a single machine, it should be unnecessary
    # to seek performance enhancement by increasing num-threads above 1.
    num-threads: 1

    # more cache memory. rrset-cache-size should twice what msg-cache-size is.
    msg-cache-size: 50m
    rrset-cache-size: 100m
   
    # Faster UDP with multithreading (only on Linux).
    so-reuseport: yes
    
    # Ensure kernel buffer is large enough to not lose messages in traffix spikes
    so-rcvbuf: 4m
    so-sndbuf: 4m
    
    # Set the total number of unwanted replies to keep track of in every thread.
    # When it reaches the threshold, a defensive action of clearing the rrset
    # and message caches is taken, hopefully flushing away any poison.
    # Unbound suggests a value of 10 million.
    unwanted-reply-threshold: 100000
    
    # Minimize logs
    # Do not print one line per query to the log
    log-queries: no
    # Do not print one line per reply to the log
    log-replies: no
    # Do not print log lines that say why queries return SERVFAIL to clients
    log-servfail: no
    # Do not print log lines to inform about local zone actions
    log-local-actions: no
    # Do not print log lines that say why queries return SERVFAIL to clients
    logfile: /dev/null
    
    # Ensure privacy of local IP ranges
    private-address: 192.168.0.0/16
    private-address: 169.254.0.0/16
    private-address: 172.16.0.0/12
    private-address: 10.0.0.0/8
    private-address: fd00::/8
    private-address: fe80::/10

Start your local recursive server and test that it’s operational:

sudo service unbound start
dig pi-hole.net @127.0.0.1 -p 5335

The first query may be quite slow, but subsequent queries, also to other domains under the same TLD, should be fairly quick.

Important steps:

In order to experience high speed and low latency DNS resolution, you need to make some changes to your Pi-hole. These configurations are crucial because if you skip these steps you may experience very slow response times:

  1. Open the configuration file /etc/dnsmasq.d/01-pihole.conf and make sure that cache size is zero by setting cache-size=0. This step is important because the caching is already handled by the Unbound Please note that the changes made to this file will be overwritten once you update/modify Pi-hole. Note: my latest updates did not change this setting. But check to verify after an update. 

  2. This command can help sudo nano /etc/dnsmasq.d/01-pihole.conf and will get you right into the file to make the change.

  3. When you’re using unbound you’re relying on that for DNSSEC validation and caching, and pi-hole doing those same things are just going to waste time validating DNSSEC twice. In order to resolve this issue you need to untick the Use DNSSEC option in Pi-hole web interface by navigating to Settings > DNS > Advanced DNS settings.

Test validation

You can test DNSSEC validation using

dig sigfail.verteiltesysteme.net @127.0.0.1 -p 5335
dig sigok.verteiltesysteme.net @127.0.0.1 -p 5335

The first command should give a status report of SERVFAIL and no IP address. The second should give NOERROR plus an IP address.

Configure Pi-hole

Finally, configure Pi-hole to use your recursive DNS server:

Upgrading Pi-hole Issues

You might have to disable the Upstream DNS Severs when you run the upgrade scripts.

Comments (1)

  1. aladamnbama

    I followed the instructions but Pi-hole is now indicating “DNS service not running” and FTL with a red dot. Under Pi-hole diagnosis I’m getting error message:

    FTL failed to start due to failed to create listening socket for port 53: Address already in use

    Please help! Let me know if more information is needed.
    RPi4B is from CryptoLab and Pi-hole and OS are both up to date.

    Thanks!!

Leave a comment

Other Posts You Might Enjoy