Running a DNS over HTTPS Client to encrypt all home DNS traffic

With DNS over HTTPS (Secure DNS), nobody listening on the wire can see the DNS queries you make when you are browsing the Internet.

If you haven't setup Secure DNS, do it today.

What is Secure DNS

Traditionally, DNS queries are sent in plaintext. Anyone listening on the Internet can see which websites you are connecting to.

To ensure your DNS queries remain private, you should use a resolver that supports secure DNS transport such as DNS over HTTPS (DoH) or DNS over TLS (DoT).

DoH providers

  • Cloudflare
  • Google
  • Cleanbrowsing
  • Comcast
  • DNS.SB
  • OpenDNS
  • Quad9


A lot of home routers do not support DoH by default, you can change router's DNS setting to point different DNS server but can not use secure DNS directly.

To solve this problem, one way is run a local DNS agent to proxy all the DNS queries through DoH or DoT.

The agent listen on DNS port 53 to receive incoming DNS query, here the query can come from router.

I use a Raspberrypi to host DoH client agent. Cloudflare provide a DoH client agent cloudflared.

Install cloudflared

Download cloudflared

Download the latest version of cloudflared:

$ wget
--2020-03-06 16:44:52--
Resolving (,,, ...
Connecting to (||:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 17677329 (17M) [application/octet-stream]
Saving to: ‘cloudflared-stable-linux-arm.tgz’

cloudflared-stable-linux-arm. 100%[=================================================>]  16.86M  5.03MB/s    in 4.1s

2020-03-06 16:44:58 (4.10 MB/s) - ‘cloudflared-stable-linux-arm.tgz’ saved [17677329/17677329]

unzip, it only include one binary file cloudflare:

$ tar zxvf cloudflared-stable-linux-arm.tgz

Check cloudflared version:

$ ./cloudflared --version
cloudflared version 2020.2.1 (built 2020-02-27-1710 UTC)

Config cloudflared

Create a config file name /usr/local/etc/cloudflared/config.yml, the content as following:

logfile: /var/log/cloudflared.log
proxy-dns: true
proxy-dns-port: 53

Install as a service

Install as a service to allow startup after reboot:

$ sudo ./cloudflared service install
INFO[0000] Failed to copy user configuration. Before running the service, ensure that /etc/cloudflared contains two files, cert.pem and config.yml  error="open /usr/local/etc/cloudflared/cert.pem: no such file or directory"

After service installed, the config file copied to /etc/cloudflared/config.yml. Future change config should change /etc/cloudflared/config.yml directly.

Enable cloudflared service

$ sudo systemctl enable cloudflared
$ sudo systemctl start cloudflared
$ systemctl status cloudflared
● cloudflared.service - Argo Tunnel
   Loaded: loaded (/etc/systemd/system/cloudflared.service; enabled; vendor preset: enabled)
   Active: active (running) since Fri 2020-03-06 17:42:52 UTC; 4h 51min ago
 Main PID: 5735 (cloudflared)
    Tasks: 14 (limit: 1772)
   Memory: 12.3M
   CGroup: /system.slice/cloudflared.service
           └─5735 /home/pi/sbin/cloudflared --config /etc/cloudflared/config.yml --origincert /etc/cloudflared/cert.pem --no-autoupdate

Mar 06 17:42:52 pi3 systemd[1]: Starting Argo Tunnel...
Mar 06 17:42:52 pi3 cloudflared[5735]: time="2020-03-06T17:42:52Z" level=info msg="Version 2020.2.1"
Mar 06 17:42:52 pi3 cloudflared[5735]: time="2020-03-06T17:42:52Z" level=info msg="GOOS: linux, GOVersion: go1.12.7, GoArch: arm"
Mar 06 17:42:52 pi3 cloudflared[5735]: time="2020-03-06T17:42:52Z" level=info msg=Flags config=/etc/cloudflared/config.yml logfile=/var/log/cloudflared.log no-autoupdate=true origincert=/etc/cloudflared/cert.pem proxy-dns=true proxy
Mar 06 17:42:52 pi3 cloudflared[5735]: time="2020-03-06T17:42:52Z" level=info msg="Adding DNS upstream" url=""
Mar 06 17:42:52 pi3 cloudflared[5735]: time="2020-03-06T17:42:52Z" level=info msg="Adding DNS upstream" url=""
Mar 06 17:42:52 pi3 cloudflared[5735]: time="2020-03-06T17:42:52Z" level=info msg="Starting DNS over HTTPS proxy server" addr="dns://"
Mar 06 17:42:52 pi3 cloudflared[5735]: time="2020-03-06T17:42:52Z" level=info msg="Starting metrics server" addr=""

Test cloudflared

Use dig to query DNS through cloudflared, you should get success DNS response:

$ dig +short @ AAAA

$ dig +short @ A

Set up router

Once DoH client agent set successfully, then change router's setting, let it DNS server point to Raspberrypi. That's it.

You can test it through Cloudflare test page.

Setup browser to use DoH

If DoH is setup properly on router, there is no need setup browser, otherwise you can also setup browser to use DoH explicitly.


Chrome 78 start support DoH, you can enable it through chrome://flags/#dns-over-https:

Secure DNS lookups

Enables DNS over HTTPS. When this feature is enabled, your browser may try to use a secure HTTPS connection to look up the addresses of websites and other web resources. – Mac, Windows, Chrome OS, Android



In about:config, search network.trr.mode and set it value to 2.


The resolver mode. You should not change the mode manually, instead use the UI in the Network Settings section of about:preferences

  • 0 - Off (default). use standard native resolving only (don't use TRR at all)
  • 1 - Reserved (used to be Race mode)
  • 2 - First. Use TRR first, and only if the name resolve fails use the native resolver as a fallback.
  • 3 - Only. Only use TRR, never use the native resolver. Up to FF >= 73, this mode also requires the bootstrapAddress pref to be set. Starting with Firefox 74, setting the bootstrap address is no longer mandatory - the browser will simply bootstrap itself using regular DNS, unless the DoH server domain can't be resolved. The native resolver will still be used for portal detection and telemetry (Bug 1593873)
  • 4 - Reserved (used to be Shadow mode)
  • 5 - Off by choice. This is the same as 0 but marks it as done by choice and not done by default.



cloudflared command line help

$ cloudflared --help
   cloudflared - Cloudflare's command-line tool and agent

   cloudflared [global options] command [command options] origin-url

   2020.2.1 (built 2020-02-27-1710 UTC)

   cloudflared connects your machine or user identity to Cloudflare's global network.
  You can use it to authenticate a session to reach an API behind Access, route web traffic to this machine,
  and configure access control.

     update     Update the agent if a new version exists
     version    Print the version
     proxy-dns  Run a DNS over HTTPS proxy server.
     service    Manages the Argo Tunnel system service
     help, h    Shows a list of commands or help for one command
   Access (BETA):
     access  access <subcommand>
     tunnel  Make a locally-running web service accessible over the internet using Argo Tunnel.

   --help, -h         show help (default: false)
   --version, -v, -V  Print the version (default: false)

   (c) 2020 Cloudflare Inc.
   Your installation of cloudflared software constitutes a symbol of your signature indicating that you accept
   the terms of the Cloudflare License (,
   Terms ( and Privacy Policy (

cloudflared command line help for proxy-dns

$ cloudflared proxy-dns --help
   cloudflared proxy-dns - Run a DNS over HTTPS proxy server.

   cloudflared proxy-dns [command options]

   --metrics value   Listen address for metrics reporting. (default: "localhost:") [$TUNNEL_METRICS]
   --address value   Listen address for the DNS over HTTPS proxy server. (default: "localhost") [$TUNNEL_DNS_ADDRESS]
   --port value      Listen on given port for the DNS over HTTPS proxy server. (default: 53) [$TUNNEL_DNS_PORT]
   --upstream value  Upstream endpoint URL, you can specify multiple endpoints for redundancy. (default: "", "") [$TUNNEL_DNS_UPSTREAM]
   --help, -h        show help (default: false)