🧠 How I Added Fallback DNS to My Pi-hole + Unbound Setup (Without Sacrificing Security)

🧠 How I Added Fallback DNS to My Pi-hole + Unbound Setup (Without Sacrificing Security)

I recently ran into an issue with my Pi-hole setup that uses Unbound as a recursive DNS resolver. Everything worked great—until some domains started failing to resolve.

🧩 The Problem

Certain domains were timing out or returning SERVFAIL, even though they worked fine when using public DNS like 1.1.1.1 or 8.8.8.8. These failures were often caused by:

  • 🧨 Broken DNSSEC validation
  • ⛓️ Misconfigured nameservers or delegation
  • 🛑 Recursive timeout failures

I didn’t want to disable DNSSEC completely, so I looked for a smarter fallback solution.

✅ The Goal

  • Use Unbound recursion by default (for privacy, speed, and DNSSEC)
  • Fallback to public DNS if recursion fails
  • Keep Pi-hole clean, using just one upstream: 127.0.0.1#5335

🛠️ The Fix: Add Fallback to Unbound

I edited the file:

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

And added this at the end:

server:
  # ... (existing settings)

  # Accept responses even if DNSSEC validation fails
  val-permissive-mode: yes

  # Fallback to public DNS if recursion fails
  forward-zone:
    name: "."
    forward-first: yes
    forward-addr: 1.1.1.1
    forward-addr: 8.8.8.8

Then I restarted Unbound:

sudo systemctl restart unbound

🔍 How It Works

  • Unbound first tries full DNS recursion (using root servers)
  • If that fails (timeout, broken delegation, etc.), it falls back to 1.1.1.1 or 8.8.8.8
  • val-permissive-mode: yes lets it accept results even with DNSSEC issues

🧪 Test It

Before:

dig example-broken-domain.com @127.0.0.1  # ❌ Times out or fails

After:

dig example-broken-domain.com @127.0.0.1  # ✅ Returns valid IP (fallback used)

🔐 Notes on Security

  • DNSSEC is still enforced when possible
  • Only if validation fails will fallback or permissive results be accepted
  • You can optionally enable logging (verbosity: 1) to monitor fallback usage

🎯 TL;DR

If you’re running Pi-hole + Unbound and want:

  • Private, recursive DNS
  • Resiliency against broken DNSSEC or delegation
  • Failover to Cloudflare/Google without modifying Pi-hole’s upstreams

Then this config is for you. Works like a charm. 🔧💨

Let me know if you’d like to apply fallback only for specific TLDs (like .xyz or .co.uk) — that’s also possible.

1 Like

No, it's the other way round:
While defining a forward zone will turn off recursion in general, setting forward-first: yes instructs unbound to resolve DNS requests first by forwarding to 1.1.1.1 or 8.8.8.8, and only if that fails, it would fall back to recursive resolution.

Quoting unbound.conf documentation:

forward-first: <yes or no>
If a forwarded query is met with a SERVFAIL error, and this option is enabled, Unbound will fall back to normal recursive resolution for this query as if no query forwarding had been specified.
Default: no

EDIT:

Setting val-permissive-mode: yes would have unbound serve replies that failed DNSSEC validation, i.e. Pi-hole would receive invalid replies.
It only makes sense to use that if you did configure Pi-hole to do DNSSEC validation:

2 Likes

So, is there a way to do so?

In this mode DNSSEC is not enforced at all. If it fails validation the result is still passed on to the client.

From man unbound.conf

The security checks are performed, but if the result is bogus (failed security), the reply is not withheld from the client with SERVFAIL as usual. The client receives the bogus data.

Yes, you are correct.
I have reverted the changes and made a Python script to fail back if the recursive Unbound is not working.

You can see it in this GitHub repo: GitHub - ordor2k/dns-fallback-pihole: If Unbound fail to retrive DNS records, it will failover to public DNS servers to retrive it.

Let me know what you think.

Port 5353 is reserved for mDNS usage, so your python proxy should use another port, and 0.3 seconds is a rather short timeout. unbound defaults to dropping DNS requests if recursion takes longer than 1.9 seconds.

To prevent clients from using invalid DNS replies, your python proxy should use upstreams that support DNSSEC and either validate their replies itself, or pass them on to Pi-hole in the same way as unbound's val-permissive-mode: yes would, so Pi-hole can do DNSSEC validation.

1 Like

Did some changes.
Let me know if it works for you.