Fully Encrypt Your Home DNS Traffic With CoreDNS
To fully secure your DNS, you’ll need two pieces of software CoreDNS and DNSProxy, both high-performance GoLang-based DNS programs that you can download from their respective GitHub Releases pages.
• Iwan Setiawan DNSServer · 10 mins read
Organization

UnixBSDShell
Traditionally, DNS requests and replies are made in plain text. These requests and replies are sent over the internet without any encryption or protection, even when you’re accessing a secure website. This has significant security and privacy implications, as these requests can be subject to surveillance, spoofing, and tracking by malicious actors, advertisers, ISPs, and others.
Your DNS server knows a lot about you—it even knows every website you visit. Between ISPs intercepting valid and invalid domains, and the possibility of selling your browsing history to advertisers, it’s both prudent and very easy to encrypt all your DNS to prevent this and, more importantly, to encrypt this typically plain text data to prevent spying.

1. SOFTWARE and HARDWARE
To fully secure your DNS, you’ll need two pieces of software: CoreDNS and DNSProxy, both high-performance GoLang-based DNS programs that you can download from their respective GitHub Releases pages.
With these two programs, we’ll set up a DNS server, DNS over TLS, and DNS over HTTPS.
Because CoreDNS and DNSProxy are so lightweight and low-resource requirements, we can easily run a fully secure local DNS server on something as small as a Raspberry Pi (I recommend a Pi 4 with 2GB for the ethernet connection only), or as something more robust like a local VM, LXD, or even a Docker container!.
2. CONFIGURATION
Configuring CoreDNS and DNS Proxy is fairly straightforward, but for DoH and DoT, you’ll need a valid TLS certificate. You can use my guide to create a CA and sign a certificate, or if you plan to use an existing domain with my partial plugin, you can sign your certificate with certbot.
a. COREDNS
Once you’ve obtained a valid certificate, you can download CoreDNS from the Releases page on GitHub for your platform: https://github.com/coredns/coredns/releases. Copy this binary to /usr/bin and mark it as executable.
$ wget https://github.com/coredns/coredns/releases/download/v1.8.4/coredns_1.8.4_linux_amd64.tgz
$ tar -xf coredns_1.8.4_linux_amd64.tgz
$ chmod +x coredns
$ mv coredns /usr/binSet
For security reasons, we’ll run CoreDNS with its own user. On Ubuntu, we can easily create this new user as follows:
$ useradd -Umrs /bin/false coredns
Create a directory to store your CoreDNS configuration, and set its ownership to CoreDNS.
$ mkdir -p /etc/coredns
$ chown root:coredns
Next, create /etc/coredns/Corefile and place the following in it. Note that in this example, we’re using a LetsEncrypt certificate make sure you adjust the path as needed.
.:1054 {
reload
errors
forward . tls://1.1.1.1 tls://1.0.0.1 {
tls_servername cloudflare-dns.com
health_check 5s
expire 3600s
}
cache 30
}
tls://.:853 {
reload
errors
tls /opt/letsencrypt/live/coredns.example.com/fullchain.pem /opt/letsencrypt/live/coredns.example.com/privkey.pem {
client_auth verify_if_given
}
forward . 127.0.0.1:1054 {
health_check 5s
expire 3600s
policy sequential
}
}
.:53 {
reload
errors
forward . 127.0.0.1:1054 {
health_check 5s
expire 3600s
policy sequential
}
}
Before we continue, let’s break down what it does from bottom to top:
b. DNS Resolver
Here we have a standard DNS resolver that forwards everything it receives to internal port 1054. Since most requests are unencrypted, this will ensure that all requests to your DNS server are forwarded to an upstream server that will ensure that the request is encrypted before leaving your network.
.:53 {
reload
errors
forward . 127.0.0.1:1054 {
health_check 5s
expire 3600s
policy sequential
}
}
c. DoT Resolver
Applications that support it can use the DNS over TLS (DoT) resolver, which does exactly the same thing as a standard DNS resolver – forwards all traffic to our upstream server on port 1054 which will encrypt everything beyond it.
tls://.:853 {
reload
errors
tls /opt/letsencrypt/live/coredns.example.com/fullchain.pem /opt/letsencrypt/live/coredns.example.com/privkey.pem {
client_auth verify_if_given
}
forward . 127.0.0.1:1054 {
health_check 5s
expire 3600s
policy sequential
}
}
d. Internal Forwarding Server
Finally, we run an internal forwarding server on port 1054. This is used internally only and ensures that all requests are forwarded to a trusted DNS server over TLS. In this example, I’m using Cloudflare, but you can use any upstream provider you prefer.
Also, if you want to add custom rules or activate any plugins, add them before the forwarding section.
.:1054 {
reload
errors
forward . tls://1.1.1.1 tls://1.0.0.1 {
tls_servername cloudflare-dns.com
health_check 5s
expire 3600s
}
cache 30
}
Next, we need to create a systemd file to start and manage CoreDNS. You can place it at /etc/systemd/system/coredns.service.
[Unit]
Description=CoreDNS DNS server
Documentation=https://coredns.io
After=network.target
[Service]
PermissionsStartOnly=true
LimitNOFILE=1048576
LimitNPROC=512
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
NoNewPrivileges=true
User=coredns
WorkingDirectory=/tmp
ExecStart=/usr/bin/coredns -conf=/etc/coredns/Corefile
ExecReload=/bin/kill -SIGUSR1 $MAINPID
Restart=on-failure
[Install]
WantedBy=multi-user.target
Finally, open the firewall on your computer for 53 and 853, and start the service.
$ ufw allow 53
$ ufw allow 853
$ systemctl daemon-reload
$ systemctl enable coredns
$ systemctl start coredns
Validate CoreDNS is running with journalctl vial, systemd status, or by checking if the process is running (ps aux | grep coredns), then you can validate it is working using dig and kdig.
e. DNSPROXY
While CoreDNS provides DNS and DoT resolvers, it doesn’t provide DNS over HTTPS or DoH resolvers, which Firefox and Chrome use as part of their “secure DNS” options. Fortunately, these are fairly easy to set up and enable.
First, download and install DNSProxy from the GitHub page in /usr/local/bin.
$ wget https://github.com/AdguardTeam/dnsproxy/releases/download/v0.38.1/dnsproxy-linux-amd64-v0.38.1.tar.gz
$ mv path/to/dnsproxy /usr/local/bin
$ chmod +x /usr/local/bin/dnsproxySetda
DNSProxy is quite easy to set up, meaning we can put all our configuration into the systemd file at /etc/systemd/system/dnsproxy.service. Typically, it creates DoH resolvers on ports 443 and 8443 for QUIC, which forward everything to CoreDNS, ensuring that everything is fully encrypted.
[Unit]
Description=DNSProxy - DoH and DoQ Proxy for CoreDNS
Documentation=https://github.com/AdguardTeam/dnsproxy
After=network.target
[Service]
PermissionsStartOnly=true
LimitNOFILE=1048576
LimitNPROC=512
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
NoNewPrivileges=true
User=coredns
WorkingDirectory=/tmp
ExecStart=/usr/local/bin/dnsproxy -l 0.0.0.0 --tls-min-version=1.2 --quic-port=8853 --https-port=443 --tls-crt=/opt/letsencrypt/live/coredns.example.com/fullchain.pem --tls-key=/opt/letsencrypt/live/coredns.example.com/privkey.pem -u 127.0.0.1:53 -p 0
Restart=on-failure
[Install]
WantedBy=multi-user.target
Finally, open the ports and start the service and you have a fully encrypted local DNS.
$ ufw allow 443
$ ufw allow 8443
$ systemctl enable dnsproxy
$ systemctl start dnsproxy
Don’t forget to update your resolve.conf file to point to your new DNS servers, or to apply your configuration network-wide, update your router configuration to advertise the IP of your DNS server running CoreDNS.
f. Validation
We can validate our configuration using dig, kdig, and curl for DNS, DoT, and DoH.
Normal DNS validation is quite straightforward:
dig www.google.com @127.0.0.1SeSe
DoT validation requires knot-dns, but once installed it can be checked by running the following command.
kdig www.google.com @coredns.example.com +tls
DoH validation is just as easy, but I personally prefer using the dog tool to validate it.
dog example.com --https @https://coredns.example.com/dns-query
Of course, you can use something like dog to validate TLS and UDP endpoints as well as TCP.
g. Modzilla Firefox and Google Chrome
Firefox and Chrome provide a few guides on how to configure them with custom DoH providers.
For Google Chrome, go to the security settings and change DoH to Custom, using the following customized URL: https://coredns.example.com/dns-query. For Firefox, the changes are identical.
The easiest way to verify Firefox is working properly is to visit about:networking#dns and see if TRR (Trusted Recursive Resolver) returns true for any domain.
Using encrypted DNS traffic is a great way to increase your privacy and security while browsing the internet. Remember that no matter which type of DNS encryption you choose, it’s more secure than no encryption at all. A proper DNS traffic filtering system can keep you and your organization safe from DNS attacks and help you save valuable resources.