Implementing DNS over TLS (DoT) on a Budget with CoreDNS

Few months back I just started to finds a new SBC-based computer to replace my super trusty beast Raspberry Pi 2 and yeah eventually settled with OrangePi zero 2. The main reason for quick replacing it because I use DoH/DoT for my daily internet connectivity needs.

While searching for another option SBC-based computer, I got the plan that want to no longer using Pi-Hole as my main DNS server and having idea that Coredns its support for running DoH/DoT based DNS.

(and the package has arrived…)

Just kickoff start the initial setup. At this moment I was choose Armbian as base OS flavor instead of using vanilla ubuntu or debian. Alternatively you can browse directly to OrangePi OS forum/docs support here .

Setup CoreDNS

Okay before setup it up, I had plan to using some automation things like Ansible (as part of new homelab plan that i want fully automate the tasks) but for now we can proceed it manually first.

Grab the CoreDNS binary using whatever download tools.

COREDNS_VERSION=1.11.1

# OrangePi Zero 2 using arm64/aarch64/armv8
wget https://github.com/coredns/coredns/releases/download/v${COREDNS_VERSION}/coredns_${COREDNS_VERSION}_linux_arm64.tgz -O /tmp/coredns_${COREDNS_VERSION}_linux_arm64.tgz

Unpack/untar that downloaded file.

tar xzvf /tmp/coredns_${COREDNS_VERSION}_linux_arm64.tgz -C .

Then move the output file into common executable path in Linux, such as placing it under /usr/local/bin. Afterward, create CoreDNS user.

sudo useradd -M -s /bin/false coredns

Create file Corefile under /etc/coredns/ then fill it up like below.

# make sure it run on port 53 and 853 (DoT)
.:53 tls://.:853 {
    # bind to ip host and local
    bind 10.10.0.2 127.0.0.1
    # hosts block if you want make it as local DNS server serve from
    # /etc/hosts
    hosts /etc/coredns/home.hosts {
        fallthrough
    }
    # important part; this case using blahdns with SG based server
    # dont forget add healtcheck :)
    forward . tls://2406:ef80:2:5ee4::1 tls://103.167.150.45 {
        tls_servername dot-sg.blahdns.com
        health_check 60s
    }
    # log the query :)
    # carefully it will spamming write actions
    log
    errors
    # No idea, but it's good to add caching mechanism
    cache {
        success 4096
        denial  1024
        prefetch 512
    }
}

After the Corefile setup, proceed to setup systemd to ensure that CoreDNS runs automatically at all times.

[Unit]
Description=CoreDNS Server
Wants=network-online.target
After=network.target network-online.target

[Service]
Type=simple
Restart=on-failure
User=coredns
Group=coredns
# i've added this to ensure restart looping 🤔
ExecStartPre=/bin/sleep 30
ExecStart=/usr/local/bin/coredns -conf /etc/coredns/Corefile
KillSignal=SIGTERM

[Install]
WantedBy=multi-user.target

Usually, NetworkManager is enabled for DNS on Debian-based distributions. Therefore, before starting the CoreDNS service, it’s important to disable the default DNS settings in NetworkManager and systemd-resolved to free up UDP port 53 for CoreDNS.

# install resolvconf
sudo apt install resolvconf -y

# set dns=default
sudo sed -i 's/^dns=.*/dns=default/' /etc/NetworkManager/NetworkManager.conf

# add this to able resolve dns from localhost
echo "nameserver 127.0.0.1" | sudo tee -a /etc/resolvconf/resolv.conf.d/head

# stop and disable it
sudo systemctl stop systemd-resolved && sudo systemctl disable systemd-resolved

Here we go for the last setup

sudo systemctl daemon-reload
sudo systemctl enable coredns
sudo systemctl start coredns

P.S. If having issue with unprivileged port, can enable this to allow <1024 port. Be carefull security risk issue.

sudo bash -c "echo 'net.ipv4.ip_unprivileged_port_start=0' > /etc/sysctl.d/99-unprivileged-ports.conf"
sudo sysctl -p /etc/sysctl.d/99-unprivileged-ports.conf

Closing Thought

So far this approach make my small machine run more efficiently less cpu/memory usage, because with this setup, the DNS server communicates directly without going through Pi-Hole first and then continuing upstream to dnscrypt-proxy while this approach also eliminate the need to maintain two different apps/services and still dont have any idea about which one best between DoT and DoH 😂😂 (need to investigate deep about that)

As my previous article , that talk about Pi-Hole with DoH before, you can directly test this configuration using tools like dns leak test or by run the command like,

dig @<your_coredns_server> <google.com>

Thank You!

Resources: