Install

# Debian / Ubuntu
sudo apt install dnscrypt-proxy

# macOS
brew install dnscrypt-proxy

# Or download the latest release
curl -L https://github.com/DNSCrypt/dnscrypt-proxy/releases/latest/download/dnscrypt-proxy-linux_x86_64.tar.gz \
    | tar -xz
sudo install linux-x86_64/dnscrypt-proxy /usr/local/bin/

dnscrypt-proxy -version

Why encrypted DNS

Default DNS is plaintext UDP on port 53. Three categories of risk:

  • Eavesdropping. Anyone on the path (ISP, coffee shop, your roommate) sees every domain you query.
  • Tampering. Same parties can rewrite responses (block, redirect, MITM).
  • Profiling. Resolvers (ISP, Google 8.8.8.8) build profiles of your queries.

DNS-over-TLS / DNS-over-HTTPS / DNSCrypt fix #1 and #2 (encryption + cert verification). Anonymized DNS adds protection against #3 by routing via a relay so the upstream resolver doesn't see your IP.

Configuration

Edit /etc/dnscrypt-proxy/dnscrypt-proxy.toml:

# Listen locally
listen_addresses = ['127.0.0.1:53', '[::1]:53']

# Pick what protocols to allow upstream
require_dnssec = true
require_nolog = true
require_nofilter = true       # set to false if you want resolvers that block ads/malware

dnscrypt_servers = true
doh_servers = true
odoh_servers = false          # Oblivious DoH if you're feeling fancy
dnscrypt_ephemeral_keys = true

# IPv4 + IPv6
ipv4_servers = true
ipv6_servers = true

# Cache
cache = true
cache_size = 4096
cache_min_ttl = 2400
cache_max_ttl = 86400

# Choose specific upstream servers (or leave empty + let dnscrypt-proxy pick)
# server_names = ['cloudflare', 'quad9-doh-ip4-port443-filter-pri', 'mullvad-doh']

# Public resolver list (auto-refreshes)
[sources]
  [sources.public-resolvers]
    urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/public-resolvers.md']
    cache_file = '/var/cache/dnscrypt-proxy/public-resolvers.md'
    minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'
    refresh_delay = 73
    prefix = ''

# Anonymized DNS routes (queries go through a relay first)
[anonymized_dns]
  routes = [
    { server_name='cloudflare', via=['anon-cs-fr', 'anon-cs-ch'] },
  ]
  skip_incompatible = true

# Forwarding rules: send certain zones to specific resolvers
# [query_log]
#   file = '/var/log/dnscrypt-proxy/query.log'

# Block specific domains
[blocked_names]
  blocked_names_file = '/etc/dnscrypt-proxy/blocked-names.txt'

[blocked_ips]
  blocked_ips_file = '/etc/dnscrypt-proxy/blocked-ips.txt'

Free port 53 from the OS

If systemd-resolved is binding to port 53 (see that tutorial):

# Edit /etc/systemd/resolved.conf
DNSStubListener=no
sudo systemctl restart systemd-resolved

# Make /etc/resolv.conf point at dnscrypt-proxy
sudo rm /etc/resolv.conf
echo "nameserver 127.0.0.1" | sudo tee /etc/resolv.conf
echo "options edns0" | sudo tee -a /etc/resolv.conf

# Or have NetworkManager stop managing it
sudo nano /etc/NetworkManager/NetworkManager.conf
# [main]
# dns=none
sudo systemctl restart NetworkManager

Start it

sudo systemctl enable --now dnscrypt-proxy
sudo systemctl status dnscrypt-proxy

# Test
dig +short example.com @127.0.0.1
nslookup -port=53 example.com 127.0.0.1

# Logs
journalctl -u dnscrypt-proxy -f

Local block / allow rules

# /etc/dnscrypt-proxy/blocked-names.txt
# Glob patterns block matching names
ads.google.com
*.doubleclick.net
*.googleadservices.com
*.googlesyndication.com
*.facebook.com           # block all of facebook
=instagram.com           # block exact match
*.tracker.example.com

For comprehensive ad/tracker blocking, point at one of the curated blocklists (Steven Black's hosts, OISD, etc.):

curl -o /etc/dnscrypt-proxy/blocked-names.txt \
    https://raw.githubusercontent.com/StevenBlack/hosts/master/alternates/fakenews-gambling-porn/hosts

For a more user-friendly ad-blocking + DNS stack, Pi-hole (see that tutorial) gives you a web UI; dnscrypt-proxy is the lightweight CLI alternative for single-machine or upstream-encryption use.

Per-domain forwarding

# Forward .lab queries to a local Pi-hole, encrypted everything else upstream
[forwarding_rules]
  forwarding_rules = '/etc/dnscrypt-proxy/forwarding-rules.txt'

# /etc/dnscrypt-proxy/forwarding-rules.txt
lab 192.168.1.10:53
internal.example.com 10.0.5.1:53

Internal LAN names resolve locally; everything else encrypted upstream.

Where to use it

  • Personal laptop on hostile networks. Coffee shop Wi-Fi can't snoop or hijack your DNS.
  • Behind a Pi-hole. Point Pi-hole's upstream at dnscrypt-proxy at 127.0.0.1:5053 — you get blocking + encrypted upstream.
  • On a router. OpenWrt has dnscrypt-proxy as an opkg; encrypts DNS for the whole LAN.
  • Server hardening. Removes "the upstream resolver sees every query this server makes."

dnscrypt-proxy vs alternatives

  • systemd-resolved with DNSOverTLS=yes (see that tutorial) — encrypted upstream, simpler, but no DNSCrypt protocol support and fewer privacy controls.
  • cloudflared — Cloudflare's DoH proxy. Locked to Cloudflare's resolvers.
  • Stubby — DoT-only stub resolver; smaller scope.
  • Unbound with DoT outgoing — full recursive resolver with TLS upstream; more powerful but heavier.
  • Pi-hole / AdGuard Home — ad-blocking-focused; include encrypted-upstream support; web UI; heavier.

Worth knowing

  • Encrypted DNS doesn't hide TLS SNI. Even with encrypted DNS, the TLS Client Hello in your HTTPS handshake contains the hostname in plaintext (unless ECH is in play). For full SNI privacy, you also need ECH-supporting clients and resolvers — growing but not universal in 2026.
  • Resolver choice matters. The encrypted-upstream resolver still sees your queries. Pick ones with no-log policies (Quad9, Mullvad DNS, NextDNS); avoid ones that profile.
  • QUIC / DoH3. Newer dnscrypt-proxy versions support DoH3 (DoH over HTTP/3 / QUIC) — even better latency on lossy networks.