Unbound with Pihole

In my setup, Unbound 1.26.1 was sending its queries to the root servers with the RD (Recursion Desired) flag set to 0. The root servers were returning REFUSED to those non-recursive queries. Unbound would then try multiple root servers, classify the responses as THROWAWAY, eventually reach 33 attempts, and return SERVFAIL.

I confirmed this by testing the root server directly with dig. A non-recursive query (RD=0) returned REFUSED, while the same query with recursion requested (RD=1) returned NOERROR with the root NS records.

I then downloaded a fresh copy of the Unbound 1.26.1 source, rather than modifying the source I had already experimented with. In iterator.c, around line 3098, I changed:

iq->chase_flags | (iq->chase_to_rd?BIT_RD:0),

to:

iq->chase_flags | BIT_RD,

This forces the RD flag on when Unbound sends the query.

I compiled the modified source and installed it. Because the custom-compiled Unbound binary did not support systemd’s notification mechanism, I also had to change the Unbound systemd service from:

Type=notify

to:

Type=simple

After that change, the Unbound service started normally.

After restarting Unbound, the same test:

dig @127.0.0.1 -p 5335 iana.org

changed from:

status: SERVFAIL

to:

status: NOERROR

with an A record returned for iana.org.

I then tested normal Pi-hole DNS traffic. The Pi-hole log showed the request being forwarded to Unbound and successfully receiving the CNAME and A/AAAA records:

2026-09-27 19:17:21.067 forwarded accounts.youtube.com to 127.0.0.1#5335

2026-09-27 19:17:21.088 reply accounts.youtube.com is <CNAME>

2026-09-27 19:17:21.088 reply www3.l.google.com is 74.125.136.139

2026-09-27 19:17:21.088 reply www3.l.google.com is 74.125.136.138

2026-09-27 19:17:21.088 reply www3.l.google.com is 74.125.136.100

2026-09-27 19:17:21.088 reply www3.l.google.com is 74.125.136.101

2026-09-27 19:17:21.088 reply www3.l.google.com is 74.125.136.102

2026-09-27 19:17:21.088 reply www3.l.google.com is 74.125.136.113

It also returned the IPv6 addresses:

2026-09-27 19:17:21.091 reply www3.l.google.com is 2607:f8b0:4002:c00::8b

2026-09-27 19:17:21.091 reply www3.l.google.com is 2607:f8b0:4002:c00::66

2026-09-27 19:17:21.091 reply www3.l.google.com is 2607:f8b0:4002:c00::65

2026-09-27 19:17:21.091 reply www3.l.google.com is 2607:f8b0:4002:c00::64

And Pi-hole subsequently queried:

2026-09-27 19:17:21.095 query[HTTPS] www3.l.google.com from 10.10.1.16

So normal DNS resolution is now working through Pi-hole → Unbound.

I also tested the setup with NordVPN/Wireguard, and Mullvad, so the issue wasn’t limited to one particular VPN provider.

In my case, forcing RD=1 on the outbound Unbound query fixed the problem. The additional systemd service change from notify to simple was necessary to run the custom-compiled Unbound binary.
::

Unbound does not set the RD bit when iterating itself. It only does when you have configured a forward-zone.
I am not sure what your configuration looks like.

Also for me the root servers always reply with a delegation regardless of the RD bit sent.

For the custom compilation you need to also provide --enable-systemd to configure for Unbound to support systemd’s notification mechanism.