Self-Hosted DNS-over-HTTPS: A Practical Setup Guide
DNS queries are still the cleartext postcards of the internet. Your ISP sees every domain you visit, and so does anyone else sharing the network. Running your own DNS-over-HTTPS resolver fixes this with minimal overhead and no dependency on third-party providers. This guide walks through setting up a personal DoH resolver in five steps.
Step 1 – Install dnscrypt-proxy
dnscrypt-proxy is the most practical tool for this job. It handles DNS encryption, caching, and upstream selection in a single binary. On Debian or Ubuntu, install it directly from the package repository. On other distributions, grab the latest release from the project’s releases page. The default configuration works out of the box, but you will want to tune it for your setup.
sudo apt update && sudo apt install dnscrypt-proxy
After installation, the service starts automatically. Verify it is running with systemctl status dnscrypt-proxy. If the status shows active and running, you are ready to move to configuration.
Step 2 – Choose Your Upstream Resolvers
The default resolver list includes several public DoH providers, but you should pick ones you trust. Cloudflare’s 1.1.1.1 and Quad9 are solid choices for privacy and reliability. Edit the /etc/dnscrypt-proxy/dnscrypt-proxy.toml file and set the server_names key to your preferred resolvers. Remove any providers you do not intend to use to reduce latency.
server_names = ['cloudflare', 'quad9']
Restart the service after editing the configuration. You can test resolution with dnscrypt-proxy -resolve example.com to confirm the resolver is responding correctly.
Step 3 – Enable DNSCrypt over HTTPS
The require_dnssec and require_nolog flags in the configuration file enforce DNSSEC validation and reject resolvers that log queries. Set both to true in the TOML file. This ensures that the responses you receive are cryptographically signed and that your resolver operator is not logging your queries.
require_dnssec = true
require_nolog = true
These two settings alone put you ahead of most users who run DNS-over-HTTPS without verifying the chain of trust. After saving the file, reload the service with sudo systemctl reload dnscrypt-proxy.
Step 4 – Point Your System to the Local Resolver
Your dnscrypt-proxy instance listens on localhost by default, typically on port 53 or 5300 depending on the configuration. You need to update your system’s DNS settings to use this local resolver instead of the router or ISP defaults. On Linux systems using systemd-resolved, edit /etc/systemd/resolved.conf and set DNS=127.0.0.1.
sudo systemctl restart systemd-resolved
Verify with resolvectl status that the DNS server is now pointing to your local instance. You can also run dig example.com @127.0.0.1 to confirm queries are being intercepted and resolved by dnscrypt-proxy.
Step 5 – Harden and Monitor the Setup
Lock down the resolver so it only listens on localhost. In the configuration file, check that listen_addresses is set to ['127.0.0.1:53'] and not bound to 0.0.0.0. This prevents your resolver from becoming an open DNS relay, which attackers could abuse for amplification attacks. Enable the query log temporarily to verify no unexpected domains are being resolved during normal browsing.
Set up a simple monitoring check with a cron job that pings the resolver every five minutes. If the service stops responding, you will know immediately rather than discovering the problem hours later when something breaks. A failed DNS resolver takes down every application on your machine, so this small investment pays for itself quickly.
Next steps
Once the resolver is stable, consider adding DNS-based ad blocking by importing a blocklist into dnscrypt-proxy. You can also expose the resolver to your local network with appropriate firewall rules if other devices on your LAN need encrypted DNS. Finally, keep an eye on dnscrypt-proxy releases for security patches, since DNS infrastructure is a high-value target for attackers.