Set up local DNS and ad blocking
As mentioned in my Valid TLS cert for local services with Traefik post, I run local services with a valid domain. I could’ve set up a custom non-existent domain + funny TLD, but creating a certificate for that would’ve made things much harder. Now I wanted to make a few services available via subdomains. I didn’t really like the fact of setting up these records on Cloudflare, where my domain is hosted, so a local DNS server was the way to go.
There are DNS servers like BIND, Knot and a few more alternatives but when setting this up, why not also block Ads and possible malicious domains at the same time? There are options like Pi-hole or AdGuardHome. For whatever reason I went with something different: blocky. I can’t even give a proper reason why I choose it. Maybe it had something to do with the fact that it is entirely written in Go and or that some benchmarks compared it against Pi-hole putting it in the first place when it comes to speed and performance.
Blocky doesn’t provide a web interface. It does have an API though. Said API provides the ability to enable/disable blocking, has an extra query endpoint and provides an endpoint to refresh the configured blocking lists. That’s it. Everything else has to be configured via its configuration file.
This is the first part of my configuration which basically handles the name resolution.
upstream:
default:
- tcp-tls:1.1.1.1:853
- tcp-tls:1.0.0.1:853
customDNS:
mapping:
example.com: 192.168.0.7
conditional:
mapping:
fritz.box: tcp+udp:192.168.0.1
168.192.in-addr.arpa: tcp+udp:192.168.0.1
17.172.in-addr.arpa: tcp+udp:192.168.0.7:15353
clientLookup:
upstream: 192.168.0.1
singleNameOrder:
- 1
As an upstream
DNS, I stick to Cloudflare’s 1.1.1.1. Blocky has the ability to perform upstream requests
via standard DNS over UDP/TCP, DoH and DoT. In my case it’s the latter: DNS over TLS. The default
keyword indicates the DNS
servers that are used as default (duh), but Blocky has the ability to group clients. If I want all my iot devices to use a
different DNS server, I could in theory do so.
The customDNS
is the main option, that makes my setup work the way it is. Blocky will return 192.168.0.7
for all queries for
example.com
, which also includes all subdomains like services1.example.com
or foobar.example.com
. This is the behaviour I
want because on this IP address, a traefik server is listening and will handle the proxying based on the host name / subdomain.
Those conditional
entries are another nice feature. DNS lookups like foobar.fritz.box
will be handled by 192.168.0.1
instead
of my configured DNS servers. The same thing works for reverse DNS lookups. In my case it’s again for normal clients in my
network and for an experimental Docker reverse DNS resolver. Somewhat redundant, but for blocky’s internal client lookup that is
being used in logs, Prometheus output etc, the clientLookup
should be configured as well.
Second part of my configuration:
filtering:
queryTypes:
- AAAA
blocking:
blockType: zeroIP
refreshPeriod: 4h
downloadTimeout: 4m
downloadCooldown: 10s
blackLists:
malware:
- https://urlhaus.abuse.ch/downloads/hostfile/
ads:
- https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt
- https://someonewhocares.org/hosts/zero/hosts
- https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
- https://raw.githubusercontent.com/notracking/hosts-blocklists/master/hostnames.txt
- https://adaway.org/hosts.txt
- https://raw.githubusercontent.com/bigdargon/hostsVN/master/hosts
- https://raw.githubusercontent.com/mitchellkrogza/Badd-Boyz-Hosts/master/hosts
clientGroupsBlock:
default:
- ads
- malware
httpPort: 4000
bootstrapDns: tcp+udp:1.1.1.1
prometheus:
enable: true
queryLog:
type: none
The filtering
settings allow me to filter out certain DNS queries. Since I didn’t have much luck with IPv6 in the past, I simply
kill all IPv6 requests.
The blocking
part is probably the most interesting one. You can configure blacklist sources. Only lists of the hosts
type are
supported. So in theory these lists can be placed in /etc/hosts
or the Windows’ hosts file. Instead of using the IP that is configured
in said lists, blocky will replace it with the IP that is configured via blockType
. Again, things can be grouped and then applied to
all or just a certain list of hosts as you can see in clientGroupsBlock
. This repository
is a good source for block lists. Blocky will handle duplicate entries by itself.
Beside that, you can configure the listening ports. Standard DNS will listen on port 53
, DoT on 853
etc. The httpPort
exposes
blocky’s internal API and prometheus endpoint. The query log can be enabled and requires further configuration. This option will
enable logging for all DNS queries to a database, console or log file. I don’t want to log anything, which is why it’s disabled.
In order configure all my local clients to use my local DNS, I simply announce it via DHCP via my FRITZ!Box router.