How to set up DoH (DNS over HTTPS) forwarder

Today we’ll set up a DoH forwarder which will act as DNS server that will accept queries and forward them to a DNS over HTTPS provider of your choosing. This is useful when you want to run a local forwarder so that your ISP or attackers cannot spy on- or manipulate your DNS queries/results.

Confusion about Cloudflare and cloudflared

Although we’ll be using cloudflared as forwarding software, you are not required to use the Cloudflare DNS servers. You can choose any server!

Cloudflare happens to provide the software called cloudflared, which can do many things, among those things is the DNS proxy (DoH forwarder) which we’ll be using. While Cloudflare also provides DNS servers, you can freely choose any DoH capable DNS servers and use them with this software which happens to be confusingly called cloudflared!

Setting things up

Download cloudflared from here and install it like this:

On Debian/Ubuntu/Mint

wget https://bin.equinox.io/c/VdrWdbjqyF/cloudflared-stable-linux-amd64.deb
sudo dpkg -i cloudflared-stable-linux-amd64.deb

On Raspberry Pi

wget https://bin.equinox.io/c/VdrWdbjqyF/cloudflared-stable-linux-arm.tgz
tar xf cloudflared-stable-linux-arm.tgz
sudo mv cloudflared /usr/local/bin/

If you’re not on a Debian/Ubuntu-based system you might have to use the RPM or download the binary (tarball) from the website, and extract the binary to /usr/local/bin/cloudflared instead. The rest of the setup is the same across all distributions. Verify cloudflared is installed correctly by running:

cloudflared --version

Which might output something like:

cloudflared version 2020.5.0 (built 2020-05-06-0335 UTC)

For security reasons we do not want to run cloudflared as root, so we’ll create a dedicated user and group for cloudflared:

sudo useradd -s /usr/sbin/nologin -r -M cloudflared

Create the file /etc/default/cloudflared:

sudo nano /etc/default/cloudflared

And add the following content:

ARGS=--address 0.0.0.0 --port 5053 --upstream https://1.1.1.1/dns-query --upstream https://1.0.0.1/dns-query

If you want to use Cloudflare DNS with malware filtering and IPv6, you might want something like this:

ARGS=--address 0.0.0.0 --port 5053 --upstream https://1.1.1.2/dns-query --upstream https://1.0.0.2/dns-query --upstream https://2606:4700:4700::1112/dns-query --upstream https://2606:4700:4700::1002/dns-query

You can adjust the upstream DoH servers to your desired ones. It does not have to be Cloudflare. You can also change the binding address and port. If you want to use it as your local system resolver, you need to set the DNS port to 53 (default DNS port).

You can add or remove upstream sources, like IPv6 if your network does or doesn’t have that. You can also go pure IPv6 if that’s your thing.

If port lower than 1024 (e.g. 53) is chosen, you’ll have to run:

sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/cloudflared

This is because normally only root is allowed to bind to ports below 1024, for security reasons.

Create the file /etc/systemd/system/cloudflared.service:

sudo nano /etc/systemd/system/cloudflared.service

And add the following content:

[Unit]
Description=cloudflared DoH proxy
After=local-fs.target syslog.target network-online.target

[Service]
Type=simple
User=cloudflared
Group=cloudflared
EnvironmentFile=/etc/default/cloudflared
ExecStart=/usr/local/bin/cloudflared proxy-dns $ARGS
Restart=always
RestartSec=10
KillMode=process

[Install]
WantedBy=multi-user.target

Now we’ll enable and start the service and verify it’s running:

sudo systemctl daemon-reload
sudo systemctl enable cloudflared
sudo systemctl start cloudflared
sudo systemctl status cloudflared

Which should return something like:

● cloudflared.service - cloudflared DNS over HTTPS proxy
     Loaded: loaded (/etc/systemd/system/cloudflared.service; enabled; vendor preset: enabled)
     Active: active (running) since Mon 2020-05-11 13:45:03 CEST; 13min ago
   Main PID: 60327 (cloudflared)
      Tasks: 16 (limit: 16602)
     Memory: 15.2M
     CGroup: /system.slice/cloudflared.service
             └─60327 /usr/local/bin/cloudflared

You can check it’s working using dig like this:

dig @127.0.0.1 -p 5053 google.com

Using it as local system resolver

Check out my previous guide on how to disable systemd-resolved and specifying your own DNS servers (make sure to set cloudflared to run on port 53 though!):

What servers to choose

I created a list of some providers here:

External Links

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.