Enhancing Internet Privacy: Setting Up DNS-over-HTTPS (DoH) on Raspberry Pi

Enhancing Internet Privacy: Setting Up DNS-over-HTTPS (DoH) on Raspberry Pi

Setting Up DoH on Raspberry Pi

In today's digital age, ensuring the security and privacy of our online activities is paramount. One effective way to achieve this is through DNS-over-HTTPS (DoH) technology, especially when implemented on a Raspberry Pi, a versatile and affordable platform. This article explores the steps to set up DoH on your Raspberry Pi, leveraging its capabilities to enhance your browsing security.

DNS-over-HTTPS encrypts DNS queries within the HTTPS protocol, making them resistant to eavesdropping and manipulation. By integrating DNS queries with regular web traffic, DoH ensures that your browsing habits remain private and protected from prying eyes.

This setup is tested on a raspberry pi (arm64) running debian 12 and acting as access point. For more details about my rpi setup, you can refer to this article:

Turn raspberry pi into a wireless access point step by step
Once configured, the Raspberry Pi will broadcast a Wi-Fi network with the SSID and password you specified during the setup process. Other devices, such as smartphones, can connect to this network and communicate with each other through the Raspberry Pi.

Install dnscrypt-proxy

Start by installing the required software packages. Open a terminal on your Raspberry Pi and execute the following commands:

VERSION=2.1.5  
wget https://github.com/DNSCrypt/dnscrypt-proxy/releases/download/${VERSION}/dnscrypt-proxy-linux_arm64-${VERSION}.tar.gz
tar -xf dnscrypt-proxy-linux_arm64-${VERSION}.tar.gz
mv linux-arm64/ /opt/dnscrypt-proxy
rm -f dnscrypt-proxy-linux_arm64-${VERSION}.tar.gz

This will install the dnscrypt-proxy in /opt/dnscrypt-proxy

💡
Make sure to use the correct download url based on your OS architecture

Configure dnscrypt-proxy

The setup already have few templates. As we will be using the proxy , we can start from example-dnscrypt-proxy.toml

cd /opt/dnscrypt-proxy
cp example-dnscrypt-proxy.toml dnscrypt-proxy.toml

To begin the configuration, we'll start by editing the dnscrypt-proxy.toml file. The key settings to adjust include server_names, listen_addresses, bootstrap_resolvers and anonymized_dns.

server_names:

This variable will hold a list of servers from https://dnscrypt.info/public-servers

My best options are:

server_names = ['ams-doh-nl','ams-doh-nl-ipv6','ams-dnscrypt-nl','ams-dnscrypt-nl-ipv6']

You can choose any server, such as those that block ads and malware (e.g., dguard-dns-doh and ams-ads-doh-nl). I haven't used these because I have my own solution. For more information, you can refer to my article:

DNS Shield for ads blocking and malwares
DnsShield is a powerful and user-friendly script designed to automate the updating process of blocklists for Dnsmasq. With DnsShield, you can effortlessly maintain an up-to-date and comprehensive blocklist, enhancing security and privacy by blocking access to malicious or unwanted domains.

listen_addresses:

Since I'm using dnscrypt proxy alongside dnsmasq, and the latest is already operating on port 53, I will configure dnscrypt to use port 54 to avoid any port conflicts.

listen_addresses = ['127.0.0.1:54']

bootstrap_resolvers:

These are normal, non-encrypted DNS resolvers, that will be only used for one-shot queries when retrieving the initial resolvers list and if the system DNS configuration doesn't work. No user queries will ever be leaked through these resolvers, and they will not be used after IP addresses of DoH resolvers have been found (if you are using DoH).

By default, this list has quad9 DNS resolver and google . For better privacy, I've replaced google DNS with cloudflare DNS:

bootstrap_resolvers = ['9.9.9.11:53', '1.1.1.1:53']

anonymized_dns:

Routes are indirect ways to reach dnscrypt servers. A route maps a server name ("server_name") to one or more relays that will be used to connect to that server.

My best list was:

 routes = [
    { server_name='ams-dnscrypt-nl', via=['anon-cs-dus4', 'anon-cs-dus3'] },
    { server_name='ams-dnscrypt-nl-ipv6', via=['anon-meganerd-ipv6', 'anon-scaleway-ams-ipv6'] },
    { server_name='ams-doh-nl', via=['anon-cs-ch2', 'anon-cs-berlin'] },
    { server_name='ams-doh-nl-ipv6', via=['anon-meganerd-ipv6', 'anon-scaleway-ams-ipv6'] },
]

You can get the relays from https://dnscrypt.info/public-servers as well and best to select the nearest possible location.

The final config file should be similar to:

server_names = ['ams-doh-nl','ams-doh-nl-ipv6','ams-dnscrypt-nl','ams-dnscrypt-nl-ipv6']
listen_addresses = ['127.0.0.1:54']
max_clients = 250
ipv4_servers = true
ipv6_servers = false
dnscrypt_servers = true
doh_servers = true
odoh_servers = false
require_dnssec = true
require_nolog = true
require_nofilter = true
disabled_server_names = []
force_tcp = false
http3 = false
timeout = 5000
keepalive = 30
cert_refresh_delay = 240
bootstrap_resolvers = ['9.9.9.11:53', '1.1.1.1:53']
ignore_system_dns = true
netprobe_timeout = 60
netprobe_address = '9.9.9.9:53'
log_files_max_size = 10
log_files_max_age = 7
log_files_max_backups = 1
block_ipv6 = false
block_unqualified = true
block_undelegated = true
reject_ttl = 10
cache = false
cache_size = 4096
cache_min_ttl = 2400
cache_max_ttl = 86400
cache_neg_min_ttl = 60
cache_neg_max_ttl = 600
[captive_portals]
[local_doh]
[query_log]
format = 'tsv'
[nx_log]
format = 'tsv'
[blocked_names]
[blocked_ips]
[allowed_names]
[allowed_ips]
[schedules]
[sources]
  [sources.public-resolvers]
    urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/public-resolvers.md', 'https://download.dnscrypt.info/resolvers-list/v3/public-resolvers.md']
    cache_file = 'public-resolvers.md'
    minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'
    refresh_delay = 72
    prefix = ''
  [sources.relays]
    urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/relays.md', 'https://download.dnscrypt.info/resolvers-list/v3/relays.md']
    cache_file = 'relays.md'
    minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'
    refresh_delay = 72
    prefix = ''
[broken_implementations]
fragments_blocked = ['cisco', 'cisco-ipv6', 'cisco-familyshield', 'cisco-familyshield-ipv6', 'cleanbrowsing-adult', 'cleanbrowsing-adult-ipv6', 'cleanbrowsing-family', 'cleanbrowsing-family-ipv6', 'cleanbrowsing-security', 'cleanbrowsing-security-ipv6']
[doh_client_x509_auth]
[anonymized_dns]
 routes = [
    { server_name='ams-dnscrypt-nl', via=['anon-cs-dus4', 'anon-cs-dus3'] },
    { server_name='ams-dnscrypt-nl-ipv6', via=['anon-meganerd-ipv6', 'anon-scaleway-ams-ipv6'] },
    { server_name='ams-doh-nl', via=['anon-cs-ch2', 'anon-cs-berlin'] },
    { server_name='ams-doh-nl-ipv6', via=['anon-meganerd-ipv6', 'anon-scaleway-ams-ipv6'] },
]
skip_incompatible = false
[dns64]
[static]

Install dnscrypt-proxy as service

After the configuration is done, it's time to install, enable and start the service:

./dnscrypt-proxy -service install
systemctl enable dnscrypt-proxy
systemctl start dnscrypt-proxy

Check the status of the service afterward to make sure it's up and running using:

systemctl status dnscrypt-proxy.service

You should get something similar to:

● dnscrypt-proxy.service - Encrypted/authenticated DNS proxy
     Loaded: loaded (/etc/systemd/system/dnscrypt-proxy.service; enabled; preset: enabled)
     Active: active (running) since Tue 2024-04-09 18:22:45 CEST; 1s ago
   Main PID: 317798 (dnscrypt-proxy)
      Tasks: 9 (limit: 9262)
        CPU: 48ms
     CGroup: /system.slice/dnscrypt-proxy.service
             └─317798 /opt/dnscrypt-proxy/dnscrypt-proxy -config dnscrypt-proxy.toml

Apr 09 18:22:45 raspberrypi dnscrypt-proxy[317798]: [2024-04-09 18:22:45] [NOTICE] Anonymized DNS: routing [ams-dnscrypt-nl] via [anon-cs-dus4 anon-cs-dus3]
Apr 09 18:22:45 raspberrypi dnscrypt-proxy[317798]: [2024-04-09 18:22:45] [NOTICE] Firefox workaround initialized
Apr 09 18:22:45 raspberrypi dnscrypt-proxy[317798]: [2024-04-09 18:22:45] [NOTICE] [ams-doh-nl] OK (DoH) - rtt: 10ms
Apr 09 18:22:45 raspberrypi dnscrypt-proxy[317798]: [2024-04-09 18:22:45] [NOTICE] Anonymizing queries for [ams-dnscrypt-nl] via [anon-cs-dus3]
Apr 09 18:22:45 raspberrypi dnscrypt-proxy[317798]: [2024-04-09 18:22:45] [NOTICE] [ams-dnscrypt-nl] OK (DNSCrypt) - rtt: 18ms
Apr 09 18:22:45 raspberrypi dnscrypt-proxy[317798]: [2024-04-09 18:22:45] [NOTICE] Sorted latencies:
Apr 09 18:22:45 raspberrypi dnscrypt-proxy[317798]: [2024-04-09 18:22:45] [NOTICE] -    10ms ams-doh-nl
Apr 09 18:22:45 raspberrypi dnscrypt-proxy[317798]: [2024-04-09 18:22:45] [NOTICE] -    18ms ams-dnscrypt-nl
Apr 09 18:22:45 raspberrypi dnscrypt-proxy[317798]: [2024-04-09 18:22:45] [NOTICE] Server with the lowest initial latency: ams-doh-nl (rtt: 10ms)
Apr 09 18:22:45 raspberrypi dnscrypt-proxy[317798]: [2024-04-09 18:22:45] [NOTICE] dnscrypt-proxy is ready - live servers: 2

It's the expected output based on the DNS routing !

Configure dnsmasq

As we have dnscrypt service ready , It's time to configure dnsmasq to use the local running server to resolve the domains. This can be simply done by adding to /etc/dnsmasq.conf:

server=127.0.0.1#54
no-resolv

The no-resolv is needed to prevent dnsmasq from using /etc/resolv.conf

💡
Make sure you only have this server defined otherwise you will have DNS leak again

Finally, restart dnsmasq using:

systemctl restart dnsmasq.service

Testing

The easiest way is to execute a DNS leak tests using https://www.dnsleaktest.com and https://browserleaks.com/dns

You should only see the configured DNS IP's. In my case, Netherlands IP's only:

As I am based on Belgium, It's working as expected based on the returned Locations 😎

In conclusion, setting up DNS-over-HTTPS on a Raspberry Pi is a proactive step towards bolstering your online privacy and security. By following these steps and leveraging the capabilities of your Raspberry Pi, you can ensure that your DNS queries remain private and secure from potential threats.

Whether you're a novice or an experienced user, implementing DoH on your Raspberry Pi is straightforward and rewarding. Stay tuned for more tips on optimizing your network security and privacy with Raspberry Pi.

Feel free to drop a comment if you need help or have questions!

buy me a coffe