Unbound always sends back SERVFAIL

Hi there,

after going through several posts and long debugging sessions, I require further support as I am not able to solve my issue.

Unbound is not able to resolve my request and always gives me back SERVFAIL, regardless of the domain I try to reach.

I am currently running Pi-Hole v6.0 on a RaspPi 5 on a fresh install (just did a complete fresh install after retrying several times to fix the error).

Expected Behaviour:

I followed the Unbound guide to the letter and everything should be fine, here is the config file which should match that of the guide (but for the logfile and verbosity while debugging):

$ sudo grep -v '#\|^$' -R /etc/unbound/unbound.conf*
/etc/unbound/unbound.conf:include-toplevel: "/etc/unbound/unbound.conf.d/*.conf"
/etc/unbound/unbound.conf.d/root-auto-trust-anchor-file.conf:server:
/etc/unbound/unbound.conf.d/root-auto-trust-anchor-file.conf:    auto-trust-anchor-file: "/var/lib/unbound/root.key"
/etc/unbound/unbound.conf.d/pi-hole.conf:server:
/etc/unbound/unbound.conf.d/pi-hole.conf:    logfile: "/var/log/unbound/unbound.log"
/etc/unbound/unbound.conf.d/pi-hole.conf:    verbosity: 3
/etc/unbound/unbound.conf.d/pi-hole.conf:    interface: 127.0.0.1
/etc/unbound/unbound.conf.d/pi-hole.conf:    port: 5335
/etc/unbound/unbound.conf.d/pi-hole.conf:    do-ip4: yes
/etc/unbound/unbound.conf.d/pi-hole.conf:    do-udp: yes
/etc/unbound/unbound.conf.d/pi-hole.conf:    do-tcp: yes
/etc/unbound/unbound.conf.d/pi-hole.conf:    do-ip6: no
/etc/unbound/unbound.conf.d/pi-hole.conf:    prefer-ip6: no
/etc/unbound/unbound.conf.d/pi-hole.conf:    harden-glue: yes
/etc/unbound/unbound.conf.d/pi-hole.conf:    harden-dnssec-stripped: yes
/etc/unbound/unbound.conf.d/pi-hole.conf:    use-caps-for-id: no
/etc/unbound/unbound.conf.d/pi-hole.conf:    edns-buffer-size: 1232
/etc/unbound/unbound.conf.d/pi-hole.conf:    prefetch: yes
/etc/unbound/unbound.conf.d/pi-hole.conf:    num-threads: 1
/etc/unbound/unbound.conf.d/pi-hole.conf:    so-rcvbuf: 1m
/etc/unbound/unbound.conf.d/pi-hole.conf:    private-address: 192.168.0.0/16
/etc/unbound/unbound.conf.d/pi-hole.conf:    private-address: 169.254.0.0/16
/etc/unbound/unbound.conf.d/pi-hole.conf:    private-address: 172.16.0.0/12
/etc/unbound/unbound.conf.d/pi-hole.conf:    private-address: 10.0.0.0/8
/etc/unbound/unbound.conf.d/pi-hole.conf:    private-address: fd00::/8
/etc/unbound/unbound.conf.d/pi-hole.conf:    private-address: fe80::/10
/etc/unbound/unbound.conf.d/pi-hole.conf:    private-address: 192.0.2.0/24
/etc/unbound/unbound.conf.d/pi-hole.conf:    private-address: 198.51.100.0/24
/etc/unbound/unbound.conf.d/pi-hole.conf:    private-address: 203.0.113.0/24
/etc/unbound/unbound.conf.d/pi-hole.conf:    private-address: 255.255.255.255/32
/etc/unbound/unbound.conf.d/pi-hole.conf:    private-address: 2001:db8::/32
/etc/unbound/unbound.conf.d/remote-control.conf:remote-control:
/etc/unbound/unbound.conf.d/remote-control.conf:  control-enable: yes
/etc/unbound/unbound.conf.d/remote-control.conf:  control-interface: /run/unbound.ctl

Unbound is listening on the correct port:

$ sudo netstat -tulnp | grep 5335
tcp        0      0 127.0.0.1:5335          0.0.0.0:*               LISTEN      32572/unbound 
udp        0      0 127.0.0.1:5335          0.0.0.0:*                           32572/unbound 

Timesync looks ok:

$ timedatectl
               Local time: Mon 2025-04-14 21:33:51 CEST
           Universal time: Mon 2025-04-14 19:33:51 UTC
                 RTC time: Mon 2025-04-14 19:33:51
                Time zone: Europe/Berlin (CEST, +0200)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no

Actual Behaviour:

$ dig pi-hole.net @127.0.0.1 -p 5335

; <<>> DiG 9.18.33-1~deb12u2-Debian <<>> pi-hole.net @127.0.0.1 -p 5335
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 28705
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;pi-hole.net.                   IN      A

;; Query time: 4356 msec
;; SERVER: 127.0.0.1#5335(127.0.0.1) (UDP)
;; WHEN: Mon Apr 14 21:32:49 CEST 2025
;; MSG SIZE  rcvd: 40
$ dig dnssec.works @127.0.0.1 -p 5335

; <<>> DiG 9.18.33-1~deb12u2-Debian <<>> dnssec.works @127.0.0.1 -p 5335
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 57901
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;dnssec.works.                  IN      A

;; Query time: 3600 msec
;; SERVER: 127.0.0.1#5335(127.0.0.1) (UDP)
;; WHEN: Mon Apr 14 21:44:22 CEST 2025
;; MSG SIZE  rcvd: 41

After running dig pi-hole.net @127.0.0.1 -p 5335 this are the last few lines of the log file (if you need more, I can attach the full log file):

[1744659169] unbound[32572:0] debug: iterator[module 2] operate: extstate:module_wait_subquery event:module_event_pass
[1744659169] unbound[32572:0] info: iterator operate: query pi-hole.net. A IN
[1744659169] unbound[32572:0] info: processQueryTargets: pi-hole.net. A IN
[1744659169] unbound[32572:0] debug: Failed to get a delegation, giving up
[1744659169] unbound[32572:0] debug: return error response SERVFAIL
[1744659169] unbound[32572:0] debug: validator[module 1] operate: extstate:module_wait_module event:module_event_moddone
[1744659169] unbound[32572:0] info: validator operate: query pi-hole.net. A IN
[1744659169] unbound[32572:0] debug: subnetcache[module 0] operate: extstate:module_wait_module event:module_event_moddone
[1744659169] unbound[32572:0] info: subnetcache operate: query pi-hole.net. A IN
[1744659169] unbound[32572:0] debug: cache memory msg=66072 rrset=66072 infra=11669 val=66368 subnet=74504
$ delv @127.0.0.1 -p 5335 +rtrace +multiline 1.debian.pool.ntp.org
;; fetch: 1.debian.pool.ntp.org/A
;; resolution failed: failure

Debug Token:

https://tricorder.pi-hole.net/gEYiMrSc/

Can you run ip route and dig +dnssec cloudflare.com @1.1.1.1 on your unbound host?

Hi, thanks.

Here are the outputs:

$ ip route
default via 192.168.50.1 dev eth0 proto dhcp src 192.168.50.229 metric 100
192.168.50.0/24 dev eth0 proto kernel scope link src 192.168.50.229 metric 100
$ dig +dnssec cloudflare.com @1.1.1.1

; <<>> DiG 9.18.33-1~deb12u2-Debian <<>> +dnssec cloudflare.com @1.1.1.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 46540
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 1232
;; QUESTION SECTION:
;cloudflare.com.                        IN      A

;; ANSWER SECTION:
cloudflare.com.         161     IN      A       104.16.132.229
cloudflare.com.         161     IN      A       104.16.133.229
cloudflare.com.         161     IN      RRSIG   A 13 2 300 20250415210615 20250413190615 34505 cloudflare.com. JF0joEyfvaQToBJM5TK8Th9FtG8PiuTK1HoGS1/8JazE/SeRe5R5QbdJ 6k+z1QOEUV7e/oXPjj0jCMHe9zMuIw==

;; Query time: 20 msec
;; SERVER: 1.1.1.1#53(1.1.1.1) (UDP)
;; WHEN: Mon Apr 14 22:09:16 CEST 2025
;; MSG SIZE  rcvd: 185

Let's check whether your unbound machine can query root servers directly, just as unbound would have to do.

Run from your machine hosting unbound, please share the output of:

dig NS . @198.41.0.4

Hi @Bucking_Horn thanks for your reply, here is the output:

$ dig NS . @198.41.0.4

; <<>> DiG 9.18.33-1~deb12u2-Debian <<>> NS . @198.41.0.4
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 7574
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 13, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;.                              IN      NS

;; ANSWER SECTION:
.                       30      IN      NS      l.root-servers.net.
.                       30      IN      NS      m.root-servers.net.
.                       30      IN      NS      a.root-servers.net.
.                       30      IN      NS      g.root-servers.net.
.                       30      IN      NS      k.root-servers.net.
.                       30      IN      NS      c.root-servers.net.
.                       30      IN      NS      i.root-servers.net.
.                       30      IN      NS      j.root-servers.net.
.                       30      IN      NS      b.root-servers.net.
.                       30      IN      NS      d.root-servers.net.
.                       30      IN      NS      h.root-servers.net.
.                       30      IN      NS      e.root-servers.net.
.                       30      IN      NS      f.root-servers.net.

;; Query time: 40 msec
;; SERVER: 198.41.0.4#53(198.41.0.4) (UDP)
;; WHEN: Mon Apr 14 22:40:50 CEST 2025
;; MSG SIZE  rcvd: 239

How about:

dig @127.0.0.1 -p 5335 1.debian.pool.ntp.org
dig 1.debian.pool.ntp.org

If the latter one also succeeds, then your issue is not with upstream accessibility in general.

EDIT: Of course, the latter one would also fail if your machine's /etc/resolv.conf would point to 127.0.0.1 while Pi-hole is using unbound as upstream.
In that case, you'd need to add a public DNS server IP to the dig statement.

In that case, you should verify whether your local time and time zone settings are correct. DNSSEC validation requires accurate time information.

Everything looks good to me.

This is where the problem lies. Your host can resolve using internet resolvers, but there is something wrong with unbound it seems. Would you happen to be running a restrictive firewall on the host, or another resolving service, such as systemd-resolved?

Try these commands:

sudo systemctl status systemd-resolved
sudo iptables -L

$ dig @127.0.0.1 -p 5335 1.debian.pool.ntp.org

; <<>> DiG 9.18.33-1~deb12u2-Debian <<>> @127.0.0.1 -p 5335 1.debian.pool.ntp.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 24336
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;1.debian.pool.ntp.org.         IN      A

;; Query time: 180 msec
;; SERVER: 127.0.0.1#5335(127.0.0.1) (UDP)
;; WHEN: Mon Apr 14 23:11:58 CEST 2025
;; MSG SIZE  rcvd: 50

As soon as I include unbound in the dig command (@127.0.0.1) the request fails, if I just use Pi-Hole as the DNS resolver, it works:

$ dig 1.debian.pool.ntp.org

; <<>> DiG 9.18.33-1~deb12u2-Debian <<>> 1.debian.pool.ntp.org
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 65417
;; flags: qr rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;1.debian.pool.ntp.org.         IN      A

;; ANSWER SECTION:
1.debian.pool.ntp.org.  130     IN      A       168.119.211.223
1.debian.pool.ntp.org.  130     IN      A       213.202.247.29
1.debian.pool.ntp.org.  130     IN      A       89.58.51.72
1.debian.pool.ntp.org.  130     IN      A       144.91.126.59

;; Query time: 24 msec
;; SERVER: 192.168.50.229#53(192.168.50.229) (UDP)
;; WHEN: Mon Apr 14 23:12:53 CEST 2025
;; MSG SIZE  rcvd: 114

@Ladrien I don't have any firewall set up in the host. Both commands did not initially return anything, as I don't have a systemd-resolved service running.

$ sudo systemctl status systemd-resolved
Unit systemd-resolved.service could not be found.

Once I installed the iptables package, nothing came back:

$ sudo iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Everything looks fine except for unbound. What method did you use to install unbound?

I think something something (ISP or modem/router) is intercepting port 53. (Recursive queries will appear to work correctly, but it will interfere with NS and SOA queries).

The output you reported for dig NS . @198.41.0.4 appears to be truncated from what would be expected if it was really 198.41.0.4 answering the query, and a telltale is that does not contain a warning about requesting recursion as would be expected from dig.

Here is an example sent from dig which really reaches 198.41.0.4:


; <<>> DiG 9.18.33-1~deb12u2-Debian <<>> NS . @198.41.0.4
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 56611
;; flags: qr aa rd; QUERY: 1, ANSWER: 13, AUTHORITY: 0, ADDITIONAL: 27
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;.				IN	NS

;; ANSWER SECTION:
.			518400	IN	NS	l.root-servers.net.
.			518400	IN	NS	j.root-servers.net.
.			518400	IN	NS	f.root-servers.net.
.			518400	IN	NS	h.root-servers.net.
.			518400	IN	NS	d.root-servers.net.
.			518400	IN	NS	b.root-servers.net.
.			518400	IN	NS	k.root-servers.net.
.			518400	IN	NS	i.root-servers.net.
.			518400	IN	NS	m.root-servers.net.
.			518400	IN	NS	e.root-servers.net.
.			518400	IN	NS	g.root-servers.net.
.			518400	IN	NS	c.root-servers.net.
.			518400	IN	NS	a.root-servers.net.

;; ADDITIONAL SECTION:
l.root-servers.net.	518400	IN	A	199.7.83.42
l.root-servers.net.	518400	IN	AAAA	2001:500:9f::42
j.root-servers.net.	518400	IN	A	192.58.128.30
j.root-servers.net.	518400	IN	AAAA	2001:503:c27::2:30
f.root-servers.net.	518400	IN	A	192.5.5.241
f.root-servers.net.	518400	IN	AAAA	2001:500:2f::f
h.root-servers.net.	518400	IN	A	198.97.190.53
h.root-servers.net.	518400	IN	AAAA	2001:500:1::53
d.root-servers.net.	518400	IN	A	199.7.91.13
d.root-servers.net.	518400	IN	AAAA	2001:500:2d::d
b.root-servers.net.	518400	IN	A	170.247.170.2
b.root-servers.net.	518400	IN	AAAA	2801:1b8:10::b
k.root-servers.net.	518400	IN	A	193.0.14.129
k.root-servers.net.	518400	IN	AAAA	2001:7fd::1
i.root-servers.net.	518400	IN	A	192.36.148.17
i.root-servers.net.	518400	IN	AAAA	2001:7fe::53
m.root-servers.net.	518400	IN	A	202.12.27.33
m.root-servers.net.	518400	IN	AAAA	2001:dc3::35
e.root-servers.net.	518400	IN	A	192.203.230.10
e.root-servers.net.	518400	IN	AAAA	2001:500:a8::e
g.root-servers.net.	518400	IN	A	192.112.36.4
g.root-servers.net.	518400	IN	AAAA	2001:500:12::d0d
c.root-servers.net.	518400	IN	A	192.33.4.12
c.root-servers.net.	518400	IN	AAAA	2001:500:2::c
a.root-servers.net.	518400	IN	A	198.41.0.4
a.root-servers.net.	518400	IN	AAAA	2001:503:ba3e::2:30

;; Query time: 111 msec
;; SERVER: 198.41.0.4#53(198.41.0.4) (UDP)
;; WHEN: Tue Apr 15 09:29:11 AEST 2025
;; MSG SIZE  rcvd: 811

Try also

dig SOA . @198.41.0.4

And the output it should be similar to the output I posted for the command above.

If it is massively truncated, (such as this example deliberately sent to cloudflare)


; <<>> DiG 9.18.33-1~deb12u2-Debian <<>> SOA . @1.1.1.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 7069
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;.				IN	SOA

;; ANSWER SECTION:
.			78442	IN	SOA	a.root-servers.net. nstld.verisign-grs.com. 2025041401 1800 900 604800 86400

then either your ISP or modem/router are interfering.

What modem/router are you using?

This has happened to people using Fritzboxes https://www.snbforums.com/threads/solved-unbound-not-resolving-anything.87269/post-872089 And Ubiquitis
http://www.reddit.com/r/pihole/comments/1ddmdvw/new_router_unbound_pihole_servfail/

2 Likes

I share robgill's view:

Your dig NS . @198.41.0.4 output implies that something upstream has intercepted DNS requests, as the WARNING: recursion requested but not available is missing, and TTLs have been decreased substantially to only 30 seconds, where the original root servers would supply 6 days.

The Fritzbox issue quoted by robgill doesn't seem related, as their digs timed out, caused by FB blocking DNS root queries when in PPoE passthrough mode (which was fixed in FritzOS 8).

Ubiquiti's ad-blocking feature seems more likely, as that would indeed force redirection of DNS traffic to Ubiquiti's DNS filter.
If your router supports a similar feature, you'd have to switch that off.

We've also had occasional reports where an ISP would offer a parental control feature, which works by redirecting DNS requests to their servers. If you were affected by that, you could consider to cancel that feature.

Furthermore, you may see similar behaviour if you were routing your network's traffic through a VPN service provider. Commonly, VPN services would redirect DNS traffic to their own DNS servers, to prevent DNS leaks.
In such a scenario, you wouldn't be able to use unbound as Pi-hole's upstream.

Thank you guys for your replies

Yesterday I was also considering the issue to lie on my router / ISP but I did not manage to further fiddle with them, I will try that again this evening as I currently don't have access to my home network.

Just for the record: I am using an ASUS RT-AX5400 Router and I have also a 3rd-party VPN service occasionally enabled with ASUS's built-in VPN fusion feature. Perhaps this could be the culprit, as @Bucking_Horn states. Although, when testing on https://dnsleaktest.com the results show only the DNS upstream servers provided by Pi-Hole (in this case OpenDNS).

Once I am able to run some tests locally and get more info, I will share back with you.

Thanks already for the great suggestions!

Might be worth checking the Asus/trendmicro AIprotection options of the router are disabled, i wouldn't be surprised if they get up to dns shenanigans.

1 Like

Thanks @robgill will also have a look at that this evening.

Just want to add this here for later as I just found another thread with a similar setup as mine, maybe is worthwhile to also consider it.