Unbound as validating, recursive, caching DNS resolver 🔹 Redis backend 🔹 Block Ads and Trackers
🔸 Compile
latest Unbound on RaspPiOS with Cache DB
and TCP Fast Open
modules.
🔸 Recursive
resolving from the root. No forwarding to other resolvers.
🔸 Redis backend database for persistent
cache. Works as second level cache.
🔸 Network wide Ads and Trackers
block. No pi-hole/adguard. No extra hop to resolve DNS.
🔸 Unbound dashboard
is available at unbound-dashboard. (Optional)
🔸 Refer to release.md
for changes and update.
-
Unbound compilation and installation is validated on
RaspberryPi OS/Debian
.Post Install
startup service and scripts may require modification for other linux distributions. -
If unbound package is installed. Take a backup of current
unbound.conf
. Remove unbound package completely:sudo apt --purge autoremove unbound
Unbound OS HW 1.19.0
raspios-bookworm-arm64-lite
Raspberry Pi 4 Model B
🔸 Redis ➜ Unbound ➜ Post Install ➜ Config ➜ Timers & Services ➜ Blocklist ➜ Start
🔸 Install ➜ Config
-
Install:
sudo apt install redis-server
-
Config:
An optimizedredis.conf
for unbound is available in the release underconfig
dir. Default redis.conf from redis 7.0.* is used as base config for the provided config. Some of the options may not be available or may be different if you are on an earlier version of redis. You can use redis.conf either from the release or your preferred one.To use the provided redis.conf, below steps can be helpful:
Edit redis config:
sudo nano /etc/redis/redis.conf
Delete everything in default redis config:
Ctrl+6
Alt+t
Ctrl+6
Copy and paste the providedredis.conf
. Save and exit nanoℹ️
Note:
Providedredis.conf
is tweaked after some thorough testing in small network. Like 4mb maxmemory has pretty optimal performance with enough cache and evict least recently used keys. Similarly snapshotting is used to save keys to database, current option will save after 2hrs if atleast 100 new keys were added or after 12hrs if at least 1 new key is added. Reboot will save database as long as snapshotting is enabled. Feel free to change them as preferred.
🔸 Packages ➜ Extract ➜ CFLAGS ➜ Configure ➜ Compile ➜ Install
-
Packages:
Install packages required for compiling unbound. Assuming gcc is already installed, below command will install 12 packages. Your environment may require additional packages. Check compilation error to find missing package (if any):sudo apt install bison flex libevent-dev libexpat1-dev libhiredis-dev libnghttp2-dev libprotobuf-c-dev libssl-dev libsystemd-dev protobuf-c-compiler python3-dev swig
-
Extract:
Download and extract unbound.Extract:
tar -xvzf unbound-release-1.19.0.tar.gz
-
CFLAGS:
Remove debugging information, otherwise unbound binary size will be much larger.Set CFLAG:
export CFLAGS="-O2"
ℹ️
Note:
Unbound binary size comparison:
➟ Debian Bookworm PrebuiltWithout Cachdb Module
➟ Compiled Without Debug InfoWith Cachdb Module
➟ Compiled With Debug InfoWith Cachdb Module
-
Configure:
Make sure you copy the full cmd and execute it inside the extracted unbound src dir../configure --build=aarch64-linux-gnu --prefix=/usr --includedir=\${prefix}/include --infodir=\${prefix}/share/info --libdir=\${prefix}/lib/aarch64-linux-gnu --mandir=\${prefix}/share/man --localstatedir=/var --runstatedir=/run --sysconfdir=/etc --with-chroot-dir= --with-dnstap-socket-path=/run/dnstap.sock --with-libevent --with-libhiredis --with-libnghttp2 --with-pidfile=/run/unbound.pid --with-pythonmodule --with-pyunbound --with-rootkey-file=/var/lib/unbound/root.key --disable-dependency-tracking --disable-flto --disable-maintainer-mode --disable-option-checking --disable-rpath --disable-silent-rules --enable-cachedb --enable-dnstap --enable-subnet --enable-systemd --enable-tfo-client --enable-tfo-server
-
Compile:
make
-
Install:
sudo make install
🔸 Add User ➜ Create Dirs ➜ Copy Files ➜ Create Crypto Keys
-
Run script
post-install.sh
available in the release underpost-install
dir. It automates post install tasks.Run:
sudo ./post-install.sh
ℹ️
Note:
Startup service and scripts are reused from unbound package in RaspberryPi OS Bookworm.root.hints
is downloaded frominternic
, it will be automated through systemd timer. -
Alternatively, create user manually and use your preferred startup service and scripts.
🔸 Update unbound and sysctl configuration files
-
A tweaked
unbound.conf
is available in the release underconfig
dir. You can use unbound.conf either from the release or your preferred one. If you use the provided unbound.conf, modify below attributes as per your environment:Change interface to Raspberry Pi IP:
interface: <IP>
Change access-control to allowed local subnet:
access-control: <subnet> allow
Change private-address to your allowed local subnet:
private-address: <subnet>
cache-min-ttl
is set to 0. Zero keeps minimum ttl of cached record as the domain owner intended. After some thorough testing in small network with different values, zero gives optimal performance withprefetch-key
andserve-expired
enabled.serve-expired-reply-ttl
is set to 0. Default is 30. Unbound changed the default value from 0 to 30 a while back following theRFC 8767
recommendation. Default nonzero value throws unbound startup⚠️
warning when cachedb module is enabled in unbound.conf undermodule-config
.ℹ️
Note:
Unbound documentation and RFC suggested to use 30 for serve-expired-reply-ttl ifserve-expired-client-timeout
(default is 0) is used. Unbound uses default 30 for serve-expired-reply-ttl irrespective of serve-expired-client-timeout.
Unbound behavior with default serve-expired-reply-ttl:
• Record served from cache ➟serve-expired-reply-ttl=30
• Record served from cachedb ➟serve-expired-reply-ttl=0
Providedunbound.conf
sets the serve-expired-reply-ttl to 0. TTL of 0 indicates that the expired record is only meant for this DNS resolution and not to be cached by the client. It removes unbound startup warning, keeps cache and cachedb behavior consistent and serve-expired-client-timeout is not used.num-threads
and variouscache-slabs
are optimized for Raspberry Pi 4 CPU. -
Modify
/etc/sysctl.conf
. Enable tcp fast open for unbound and change virtual memory commit mode for redis warning.Edit:
sudo nano /etc/sysctl.conf
Add below lines at the end:
################################################################### # Unbound & Redis # # Unbound: Enable TCP Fast Open - Reduces Network Latency net.ipv4.tcp_fastopen=3 # # Redis: Recommended To Use 1 - Removes Redis Log Warning # Kernel Virtual Memory Overcommit Mode # 0 Heuristic overcommit (Default) # 1 Always overcommit, never check # 2 Always check, never overcommit vm.overcommit_memory=1
🔸 Automate blocklist and roothints update with systemd timers
-
Run script
install-timers.sh
available in the release underinstall-timers
dir. Installs systemd timers, services and scripts forroot servers
andblocklist
update.Run:
sudo ./install-timers.sh
ℹ️
Note:
Timers update:
•root servers
➟ Monthly on the last Sunday at 3:55am
•blocklist
➟ Monthly on the last Sunday at 4:00am
You can change the time and frequency in/etc/systemd/system/unbound-roothints.timer
and/etc/systemd/system/unbound-blocklist.timer
-
Alternatively, use your preferred method for blocklist and roothints update.
-
Create dir and empty blocklist:
sudo mkdir -p /opt/unbound/blocklists
sudo touch /opt/unbound/blocklists/unbound.block.conf
ℹ️
Note:
/opt/unbound/scripts/update-blocklists.sh
script uses StevenBlack'sunified hosts (adware + malware) + porn
as default list. It converts default list to unbound format, removes comments and sorts it.
You can add more lists to the update-blocklists.sh script. With some basic expertise insed
you can aggregate multiple lists into unbound blocklistunbound.block.conf
🔸 Initial run
-
Let's do the initial run. Start
unbound
, manually updateroot servers
andblocklist
.Enable unbound:
sudo systemctl enable unbound
Start unbound:
sudo systemctl start unbound
Update root servers:
sudo /opt/unbound/scripts/update-roothints.sh
Update blocklist:
sudo /opt/unbound/scripts/update-blocklists.sh
🔸 Verfiy unbound and redis
-
Unbound resolving the DNS:
Run:
dig whoami.akamai.net
Returns your WAN IP.Run:
dig +ttlunits github.com
Returns github IP in the ANSWER SECTION and raspberry pi IP where unbound is running in the SERVER. -
Redis saving the cache:
Run:
redis-cli dbsize
Count starts increasing with each unbound DNS lookup request.
🔸 Few handy cmds
-
Unbound:
Stats:
sudo unbound-control stats_noreset | grep total
Tail log:
sudo journalctl -u unbound -n 200 -f
Tail filtered log:
sudo journalctl -u unbound -n 200 -f | grep "10.1.5.30\|10.1.5.32"
Check config for errors:
unbound-checkconf /etc/unbound/unbound.conf
-
Redis CLI:
Db size:
redis-cli dbsize
Memory stats:
redis-cli info memory | grep human
Monitor live queries:
redis-cli monitor
-
Enable Redis Unix Socket:
Unbound (1.18.0) added the option to connect to redis server over unix socket. It has better throughput. Follow below steps to enable unix socket connection between unbound and redis:-
Redis config:
Edit:
sudo nano /etc/redis/redis.conf
Add options:
unixsocket /var/run/redis/redis.sock
unixsocketperm 707
Restart redis:
sudo systemctl restart redis-server
-
Unbound config:
Edit:
sudo nano /etc/unbound/unbound.conf
Modify under
cachedb:
tag:Add:
redis-server-path: "/var/run/redis/redis.sock"
Comment out:
#redis-server-host: 127.0.0.1
#redis-server-port: 6379
Restart unbound:
sudo systemctl restart unbound
ℹ️
Note:
In order to use more restrictive optionunixsocketperm 770
inredis.conf
, add unbound user to redis group.
Redis connectivity on TCP can be turned off with optionport 0
in redis.conf. When redis is not listening on TCP, specify socket path in cli cmdsredis-cli -s /var/run/redis/redis.sock
-
-
Resolver Configuration:
Make sure/etc/resolv.conf
has only RaspberryPi IP name servers.NetworkManager
in RaspberryPi OS Bookworm will make this change automatically if your router's LAN DNS is pointing to Raspberry Pi IP.nameserver <RaspberryPi-IP>
-
Add LAN DNS:
According to your router, change LAN DNS to Raspberry Pi IP. DNS setting under internet setup is WAN DNS, it is not same as LAN DNS. If router permits to change LAN DNS, it is usually under LAN setup. -
Troubleshoot Blocked Domain:
Below option logs blocked domains, using that you can find domain causing the issue.Edit:
sudo nano unbound.conf
Set:log-local-actions: yes
-
Block Selective:
Specific domains can be blocked for specific IPs with tag options. It works on top of existing ads and trackers block. Providedunbound.conf
has selective block configuration commented out under|Block|
. If interested uncomment it and replace the IPs and domains.ℹ️
Note:
Provided specific block configuration handles simple use case pretty well. For complex scenarios utilize unbound RPZ. -
DNS Lookup:
To inspect if the record is served from redis cachedb.Increase log verbosity briefly:
Run:sudo unbound-control verbosity 4
Tail log in separate terminal:
Run:sudo journalctl -u unbound -n 200 -f
Run:
dig github.com
ANSWER SECTION in the log shows that DNS lookup is responded from redis cache:
info: redis ;; ->>HEADER<<- ...
Revert log verbosity:
Run:sudo service unbound reload
-
Uninstall Unbound:
Unbound can be uninstalled by running below cmd in the build directory.sudo make uninstall
After uninstall all the
Post Install
andTimers & Services
steps can be easily reverted by runningpost-remove.sh
provided in the release.sudo ./post-remove.sh