As everyone in the networking field knows, DNS is one of the most important things on the internet, the one that resolves the names of the IP addresses. But if you are working in a server or a service that requires fetching other domains and not just serving content (Like Invidious and Matrix) you don’t really want to make a DNS request EVERY TIME right?

This leads to latency problems and redundancy because you don’t really need to ask the DNS server: “HEY FUCKER, GIVE ME THE IP ADDRESS OF youtube.com” everytime you access youtube, the DNS server will respond like this: “TAKE THIS, THIS IS THE IP ADDRESS AND STOP REQUESTING ME SHIT PLEASE, I NEED TO SERVE MORE CLIENTS”.

So that is where DNS Caching comes in, you just ask the DNS server the IP of the domain name that you are requesting, the DNS server replies with the IP address and you save that IP for a period of time so you don’t make a thousand of DNS requests with the risk of being rate limited of if the DNS server works like shit (It is slow or down, etc, etc…).

DNS Proxy is one of the many DNS clients that are capable of doing DNS Caching but this one comes with really handy features like being compatible with almost any protocol of DNS: DNS-over TLS, HTTPS, QUIC, and DNSCrypt (For HTTPS only if I remember well. I never tested in depth…)

How to install DNS Proxy

This will depend of your linux distro, on Arch Linux you can install it from the AUR with an AUR helper searching for dnsproxy-git (My package lol) or the binary dnsproxy

In any other distro you need to download the latest release from dnsproxy GitHub and download the correct one, if you don’t know which one you need to download, click on the one which contains arm64 in the name. For example: dnsproxy-linux-amd64-v0.54.0.tar.gz.

Then just use this commands in the console:

  • tar -xvf dnsproxy-linux-amd64-v0.54.0.tar.gz (Replace the name of the tar.gz if the version is different obviously)
  • sudo mv linux-amd64/dnsproxy /usr/bin/dnsproxy

Creating a SystemD service.

If you use the AUR package you can skip this step

Other thing you would want to do is keeping DNSProxy running in background, starting on startup and restarting itself if something goes wrong. For that you would need a systemd service for it making it more easy to manage

Put this into a file named /usr/lib/systemd/system/dnsproxy.service:

[Unit]
Description=Simple DNS proxy with DoH, DoT, and DNSCrypt support
Documentation=https://github.com/AdguardTeam/dnsproxy#readme
After=network.target
Before=network-online.target

[Service]
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
DynamicUser=yes
ExecStart=/usr/bin/dnsproxy --config-path=/etc/dnsproxy/dnsproxy.yaml

[Install]
WantedBy=multi-user.target

And done. DNS Proxy has been installed but you will need to update it manually, redownloading the tar.gz and copying the dnsproxy binary into /usr/bin/dnsproxy. If you use Arch Linux with just update it using your preferred AUR helper.

DNSProxy configuration

This is really easy to do, the config syntax is really simple. Create /etc/dnsproxy/dnsproxy.yaml and paste this into the file (If you installed it via an AUR helper you don’t need to paste anything, you just have to modify it a little bit):

# Any command-line options specified will override the values from the
# config file

---
## Required
upstream:  # At least one upstream is required
  - 76.76.2.0:53

## Recommended
tls-min-version: 1.2
http3: true  # dnsproxy automatically picks the fastest HTTP(S) protocol
refuse-any: true

## Optional
listen-addrs:
  - 127.0.0.1
cache: true  # THIS ENABLES DNSCACHING
verbose: true  # Increase verbosity for debugging

This config enables you to use 76.76.2.0 (ControlD DNS) and listen in the loopback address with DNS Caching. Now start the dnsproxy service using systemctl start dnsproxy.

To test if it works, use this command in the console: dig @127.0.0.1 zzls.xyz

You should get a response like this:

; <<>> DiG 9.18.18 <<>> zzls.xyz
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 7183
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

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

;; ANSWER SECTION:
zzls.xyz.		600	IN	A	199.195.254.68

;; Query time: 97 msec
;; SERVER: 127.0.0.1#53(127.0.0.1) (UDP)
;; WHEN: Wed Aug 23 13:33:46 -04 2023
;; MSG SIZE  rcvd: 53

If it resolves the IP address without any problems you now can edit the /etc/resolv.conf and include this line:

nameserver 127.0.0.1

That line should be at the start of the file or above of any other nameserver option. Here is an example:

# Primary
nameserver 127.0.0.1
# Secondary / Backup
nameserver 76.76.2.0

And now your system will talk directly to DNSProxy but with the advantage of being more fast resolving domains that were resolved previously.

Remember to enable the dnsproxy systemd service so it starts automatically at startup (Or you will get a lot of DNS errors…)

You can see more detailed info here: https://github.com/AdguardTeam/dnsproxy

https://github.com/AdguardTeam/dnsproxy/blob/master/config.yaml.dist

Example configs

---
## Required
upstream:  # At least one upstream is required
 - https://cloudflare-dns.com/dns-query
 - https://mozilla.cloudflare-dns.com/dns-query
 - https://dns9.quad9.net/dns-query
   #- quic://p0.freedns.controld.com

bootstrap: # This fetches the domains of the upstreams
  - "9.9.9.9:53"
  - "1.0.0.1:53"

## Recommended
tls-min-version: 1.2
http3: true  # dnsproxy automatically picks the fastest HTTP(S) protocol

listen-addrs:
  - 127.0.0.1
listen-ports: 
  - 53
cache: true
cache-size: 1024
verbose: false
ipv6-disabled: true

This one is what I used to use on my server, using DNS-over-HTTPS because of security.

---
## Required
upstream:  # At least one upstream is required
  - quic://dns.nextdns.io

bootstrap:
  - "1.0.0.1:53"
  - "9.9.9.9:53"

listen-addrs:
  - 127.0.0.1
cache: true
verbose: false
cache-min-ttl: 600 
fastest-addr: true

And this one is one that I use on my PC using DNS-over-QUIC

Troubleshoot

My resolv.conf is being overwritten!!!

Some programs “manage” the /etc/resolv.conf changing the contents of it when there is a change on the network.

DHCPC

If you are using dhcpc as your DHCP client for your server of your PC, you will notice that the resolv.conf file is being overwritten without you knowledge. To solve this add this line to your /etc/dhcpcd.conf

nohook resolv.conf

Then restart the dhcpcd service and done.

NetworkManager

If you use NetworkManager you will notice that the resolv.conf has a line that says something like this # Managed by NetworkManager. This means NetworkManager will overwrite the resolv.conf file depending of your actual network connection (E.g: It will use your ISP DNS server if you are connected to your router).

To prevent this, add these two lines into the file /etc/NetworkManager/conf.d/dns.conf (If the file and folder doesn’t exists, just create them xd):

[main]
dns=none

Others

See https://wiki.archlinux.org/title/Domain_name_resolution#Overwriting_of_/etc/resolv.conf