pihole-FTL + unbound with Cache DB Module Options (Redis)

Assumption: you have managed to run /home/pi/compile_unbound.sh and both Unbound and Redis are installed on your system, using the default settings that come with the packages.

The GitHub repository has a directory structure, you need to duplicate this, and copy the files on your system.
If unbound compiled successfully, /etc/unbound already exists. You need to get the RAW content of the file /etc/unbound/unbound.conf and copy (use WinSCP) the content on your system (same location). This file tells unbound to use all of the configuration files in /etc/unbound/unbound.conf.d, a folder you need to create yourself on your system.

Using the same method, you used to copy the file /etc/unbound/unbound.conf, you now need to get the RAW content of all (4) files in /etc/unbound/unbound.conf.d and copy the content on your system.

WARNING: the content of /etc/unbound/unbound.conf and /etc/unbound/unbound.conf.d/unbound.conf is different, don't copy the same content twice!!!

The file /etc/unbound/unbound.conf.d/unbound.conf contains IP addresses. You need to change them to work on your system. If you don't know how to do that, simply:

  • remove the lines interface: 127.10.10.2@5552 and interface: fdaa:bbcc:ddee:2::5552@5552
  • uncomment the line #port: 5552 (remove the # sign) and change the number into 5353 (resulting line: port: 5353).
  • If you don't have IPv6 on your system, change the line do-ip6: yes into do-ip6: no

The changed settings are the same as the settings, explained in the pihole documentation for unbound, this will allow you to follow the rest of that guide, to complete the pihole configuration.

After you've completed copying and changing the fhe configuration files, run unbound-checkconf to verify you haven't made any mistakes.

If everything is OK, run sudo service unbound restart, this will start unbound with the new config, and check if unbound is really running (sudo service unbound status)

now complete the setup, following the instuctions from the pihole guide, starting at Start your local recursive server and test that it's operational (skip sudo service unbound start, we've already done that.

Suc6

1 Like

What is not clear to me: Why do you want to do this?

From unbound.conf:

When Unbound cannot find an answer to a query in its built-in in-memory cache, it consults the specified backend. If it finds a valid answer in the back- end, Unbound uses it to respond to the query without performing iterative DNS resolution. If Unbound cannot even find an answer in the backend, it resolves the query as usual, and stores the answer in the backend.

My interpretation of this: DNS records get stored in this new external database and do never expire (unless done manually).

What would be the drawback of achieving the same thing in Pi-hole (dnsmasq) or unbound without the Redis detour? This could easily be done by artificially forcing the TTL value to say weeks or months (?)
Yes, min-cache-ttl is limited to one hour in pihole-FTL (for good reasons!) but this limit can obviously be modified when you are fine with compiling locally anyways:

According to tests, performed by @GieltjE (not sure what method was used to perform the test), it makes the system faster.
If, NOT yet sure about this, once a key has been created in the Redis database, there would be no more outgoing DNS queries, thus limiting the number of DNS queries for any given record to one (1). This would limit any analysis of DNS request, it would show you visited a site, but not how often. A comment of @GieltjE on a dutch forum indicates his test showed outgoing DNS queries DO happen, despite the entry in the Redis database. If that is correct, it would indeed make the Redis approach an unnecessary detour, as you indicated.
No answer found yet, searching..., why would the unbound developpers create such a mechanism, if all it does is add unnecessary overhead. It probably is an advantage under certain conditions, which need yet to be discovered, the only reason, mentioned by @GieltjE would be increased performance (if the test is valid - no offence).

Maybe you can dig out a pull requests or some meaningful commit messages on unbound's side revealing their motivation?

This should already happen with the cache inside Pi-hole. Admittedly, if the TTL is too small, the domain could be re-queried if you visit the page once an hour or once a day or so, however, here you could artificially increase the min-cache-ttl value to achieve the very same thing, can't you?

The only "drawback" I see is that Pi-hole's cache does not survive restarts, however, even I -- as the main FTL developer -- do not restart my production Pi-hole more than once to twice a week. Typical users run FTL for months without interruption.
Querying a page twice a week does not tell my ISP (or whomever you try to hide from) much. Using unbound already spreads the knowledge across name servers. My feeling is that you should at least query a domain once a week to ensure that you don't loose connectivity to this page.

@jpgpi250 I think a few things got lost in translation or I wasn't clear.

With redis the correct TTL is honored so switchting to redis doesn't bring any downsides compared to (just) pi-hole's FTL (in fact the behaviour is exactly the same!). This was verified using the pi-hole's interface and an external DNS server and a temporary subdomain with a short TTL.

On the tweakers.net forum I also mentioned the testing that was performed, which basically boils down to the pi-holes benchmarking page with unlimited domains which was filtered for unique items.
That resulted in a 31k long list which gave a 5 minutes advantage for redis (28min vs 33,5min without redis).
This might not be conclusive testing because this is a sequential test, but it does show a good gap between using redis or the built in FTL cache.
Also noted on the tweakers forum is the fact that singular queries without an extra induced load are too fast for benchmarking. But that even our two person household generate enough different entries (31k) to be relevant during consecutive queries.
Another side note presented is that on sd-cards it is best to disable the redis disk cache.

pihole-FTL is restarted, and thus clears it's cache, at least once a week, ref your reply here (building the tree to the (weekly)), without user intervention. I have no idea if pihole-FTL is automatically restarted when adding a whitlist, blacklist or regex entries, using the web interface, you might want to clarify this.
I sometimes restart pihole-FTL, but never restart unbound, unless I run into serious problems or change the configuration, hence the idea to 'favour' the unbound caching methods over the pihole-FTL cache.
I'ts sunday 12h23, so pihole -g ran last night. I cleared all caches yesterday morning, trying to get some meaningfull figures. Currently I have 658 entries in the pihole-FTL cache and 784 entries in the Redis database, meaning unbound 'knows' more than pihole-FTL, which is the goal...
I am aware these figures don't mean much yet, the system hasn't been up long enough to draw conclusions.

It's NOT my intention to argue or offence participants here, just want to know the pro/con/… of the solution

As far as I know, blocked domains requests never make it to unbound, they are handled and responded to directly by pihole-FTL. The Redis count would never increase if the domain is blocked.

I'm sorry, but I still don't see the need to add more moving gears (Redis). Even with

Simply move my idea from overwriting the minimum TTL (even though I still consider this a bad idea, but leave that aside for the moment) from Pi-hole into unbound if this is a point with less movement?

What speaks against artificially increasing the minimum TTL in unbound for your use case?

cache-min-ttl: <seconds>
Time to live minimum for RRsets and messages in the cache. Default is 0. 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 any more.


I understand this and I'm not trying to argue against you, I'm just not yet convinced that we can win anything with Redis being part of the game compared to using existing resources (unbound's own cache). In fact, I see many advantages of handling this in the DNS resolver's own cache rather than in Redis, the only point against this, I've noticed so far is the survival of a restart (which doesn't seem to happen often with unbound).

Maybe unexpected, but by keeping track of the ttl in redis a lot of potentially bad cache is automatically discarded.

Found a discussion here which might explain some things.

@GieltjE: On tweakers.net, you stated (translation) as soon as de Redis cache provides an expired record, a new query is performed. This appears to be correct, but the request is (see below) performed after the response is provided to the client, this to update the expired entry (see below - prefetch=yes).

I, and probably others, added prefetch=yes to my unbound config, as the result of a discussion (@DL6ER - Everyone of the team agreed to remove the lines) , where it was decided to remove cache-min-ttl and cache-max-ttl from the recommended unbound config, so the behavior @GieltjE has seen is probably because of the prefetch=yes setting.

The expired record will be served to the client only, if the setting serve-expired: yes is configured, as pointed out by @anon55913113.

So I changed my unbound config, ensuring the following settings are already there or added, and there are no cache-xxx-ttl settings in the config.:

prefetch: yes
serve-expired: yes
serve-expired-ttl: 0
serve-expired-ttl-reset: yes

Some questions remain, regarding the use of Redis, as pointed out by @DL6ER (I still don’t see the need to add more moving gears)

Restarted unbound, emptied the Redis cache (redis-cli FLUSHALL), so it's to soon to tell what the result will be, however, it remains fascinating and worth discussing...

So far I used

to limit serving, not serving too old records and force a refresh after some time.

Redis users, be aware of the fact that Redis writes a lot of log entries (when performing database saves) to /var/log/redis/redis-server.log

to over come this (killing your SD card) I added the following

/etc/fstab

tmpfs /var/log/redis tmpfs nodev,nosuid,gid=adm,uid=redis,mode=2750,size=16M 0 0

/etc/logrotate.d/redis-server

/var/log/redis/redis-server*.log {
        daily
        missingok
        rotate 1
        compress
        notifempty
}

continuing to try to understand Redis

first, increase unbounds verbosity: sudo /usr/sbin/unbound-control verbosity 5

Don't forget to decrease the verbosity or restart unbound, after you're done, or your unbound log will explode.

some entries found in the unbound log:

Oct 21 12:29:39 unbound[15130:0] debug: redis_lookup of BB4FC6A97D927FBBAC80E218                                                                                                             B91B9A126683A2B795378885CEF766EC85E81FDE
Oct 21 12:29:39 unbound[15130:0] debug: redis_lookup: no data cached

Oct 21 12:29:39 unbound[15130:0] debug: redis_store DC9B09CE18ABA23DB4FC71D86033A74F67B73D9AA106BECA6192C0512AE16079 (73 bytes)
Oct 21 12:29:39 unbound[15130:0] debug: redis_store set completed

Oct 21 12:34:23 unbound[15130:0] debug: redis_lookup of 8D825D767F185F94C89F48EC5C5A87BC3751CA17DEDE6940ABF62EEF2A5C209D
Oct 21 12:34:23 unbound[15130:0] debug: redis_lookup found 875 bytes
Oct 21 12:34:23 unbound[15130:0] info: redis ;; ->>HEADER<<- opcode: QUERY, rcode: NOERROR, id: 0

These are random entries (not related) from the log. Especially the last one proves Redis is really doing something, even on a system where unbound hasn't been up very long (see my last entry, regarding prefetch=yes)

Oh yes, but you see there also the reason for why it still wasn't changed - I put it on some paper and then forgot. Problem is that I'm traveling as well now. If you want to submit a docs PR I'd be happy approving and merging it.

Is this a also starting from an empty Redis database?

I'm repeating myself here, but I still don't see what Redis effectively brings into play with serve-expired: yes besides a possible restarting resistance.

For me that is already a reason or advantage.

I noticed another, probably important sentence in the unbound documentation:

The thread waiting for a response from the Redis server cannot handle other DNS queries.

To my understanding, this means a change to the num-threads setting will also be required, this to avoid delays

num-threads: 2

anybody agrees / disagrees?

Where can I find instructions on how to do that without causing problems?

To ensure I don't need to troubleshoot Redis problems, I've added the following:

  1. Script, /etc/unbound/clearRedisDB.sh, content:

#!/bin/bash
redis-cli FLUSHALL

  1. Add line to /lib/systemd/system/unbound.service, content:

ExecStartPre=/etc/unbound/clearRedisDB.sh

This empties the Redis cache whenever unbound starts, so both caches where empty before this log entries where entered.

Indeed "prefetch: yes" is in my unbound config, but the serve-expired rows are not present.
What is the best config to adhere to the RFC's?

Answering my own question here. Found this document on how to optimize unbound
On a raspberry pi 3B and 3B+, this would imply the correct setting on a 3B would be num-threads: 4

With the great help of @mibere (hank you for this), I've made some changes to my unbound config. This implies unbound needs to be compiled with an additional option: --with-libevent, which requires the installation of libevent-dev (sudo apt-get -y install libevent-dev).

I've already applied some of the proposed settings, not all (yet), and have updated my GitHub repository to reflect the changes.

Feel free to comment on / discuss the settings in these configuration files.

Not sure, but I don't expect Redis to have a great impact (if any), when these settings are not present. To verify this, you could increase the verbosity of unbound, and check the unbound log for entries containing redis_lookup found (sudo cat /etc/unbound/unbound.log | grep redis - use the correct location). It's a lot of logging (verbosity 5), so ensure you have sufficient disk space...
I'm still using my initial settings, evaluating this and keeping the proposed settings from @mibere in mind (see above).

Fork GitHub - pi-hole/docs: The official Pi-hole documentation and submit a PR against master (there is no development branch on this repo). After the PR has been merged, the changes will be automatically deployed to https://docs.pi-hole.net

Thanks for this information. It is useful