For Pi-hole on Ubuntu Server 24.04, route its upstream requests through dnscrypt-proxy and point Pi-hole to the local listener at 127.0.0.1#5053. This encrypts DNS traffic between your server and the selected upstream resolver with DNS-over-HTTPS (DoH), while Pi-hole continues to answer your LAN clients and apply its blocklists. Pi-hole itself does not provide DoH transport to its upstream by default; the local proxy supplies that encrypted connection.
There is a current-version detail to know first: Cloudflare removed the cloudflared proxy-dns command from new releases starting February 2, 2026. Older tutorials that install that command may not work with a current cloudflared release. The steps below use dnscrypt-proxy, following Pi-hole’s current DoH guide. This setup is suitable when Pi-hole and the proxy run on the same Ubuntu host. A Docker or multi-host setup needs different listener addressing and firewall rules.
What this setup does and what it does not do
Normal DNS usually sends queries from your resolver to an upstream DNS provider without transport encryption. DoH carries DNS requests inside HTTPS, making it harder for a network observer between your Pi-hole server and the resolver to read or alter those requests. Pi-hole remains the DNS server advertised to devices on your local network; only its upstream path changes.
DoH does not make DNS activity invisible to the resolver you choose. The upstream provider still receives queries from your server, and Pi-hole may retain client query history according to its privacy and logging settings. HTTPS also does not encrypt unrelated web traffic. If your goal is to use a particular resolver, check its privacy policy and choose its DoH entry from the supported resolver list.
Before you begin
- Confirm that Pi-hole is already installed and working on Ubuntu Server 24.04. This walkthrough configures an existing Pi-hole rather than installing it.
- Make sure the server has a stable LAN address. If the address changes, router DHCP clients may lose their DNS server.
- Have administrator access and a way to reach the Pi-hole host if DNS temporarily stops working. Avoid making this change remotely over a connection that depends on the same Pi-hole for name resolution.
- Record the current Pi-hole upstream settings so you can restore them during rollback.
The proxy will bind only to loopback on port 5053, leaving port 53 for Pi-hole. This avoids competing with Pi-hole’s DNS service and Ubuntu’s local resolver. Do not disable systemd-resolved just to make this design work; the proxy’s separate loopback port avoids that conflict.
1. Install dnscrypt-proxy from Ubuntu’s package repositories
The dnscrypt-proxy project documents an Ubuntu package installation route. Check that your configured Ubuntu repositories offer a candidate before installing:
sudo apt update
apt-cache policy dnscrypt-proxy
If the output shows a candidate version, install it:
sudo apt install dnscrypt-proxy
If no candidate is shown, do not add an unrelated third-party repository just to proceed. Use the installation method linked from the dnscrypt-proxy project’s official Linux guide, verify the release and architecture, and adapt the service setup to that installation. The systemd socket unit and configuration paths below apply to the Ubuntu package setup documented by Pi-hole.
2. Move the proxy listener to localhost port 5053
Pi-hole already uses the standard DNS port 53. Configure the proxy’s socket to listen on both TCP and UDP at 127.0.0.1:5053, reachable only from the same host. Create a systemd drop-in:
sudo systemctl edit dnscrypt-proxy.socket
Enter these lines in the editor and save:
[Socket]
ListenStream=
ListenDatagram=
ListenStream=127.0.0.1:5053
ListenDatagram=127.0.0.1:5053
The empty ListenStream= and ListenDatagram= lines clear the package defaults before setting the replacement addresses. Do not omit them: systemd can otherwise keep the default port in addition to the custom listener.
3. Select a DoH resolver
Open the package configuration file:
sudoedit /etc/dnscrypt-proxy/dnscrypt-proxy.toml
For systemd socket activation, use an empty listener list in the proxy configuration. Choose a resolver name from the current signed public resolver list. For example, the following selects the standard Cloudflare resolver; the Pi-hole guide also shows cloudflare-security as an example when malware filtering at the upstream resolver is wanted:
listen_addresses = []
server_names = ['cloudflare']
Keep the rest of the package’s configuration intact. The names in server_names are registry identifiers, not arbitrary hostnames or URL paths. If you prefer another provider, verify that its current resolver entry supports DoH and copy its exact name. A resolver that filters malware or other categories may produce different results from an unfiltered resolver.
4. Point Pi-hole to the local proxy
Set Pi-hole’s upstream DNS address to the local listener:
sudo pihole-FTL --config dns.upstreams '["127.0.0.1#5053"]'
The #5053 suffix is Pi-hole’s notation for the nonstandard DNS port. You can also check the Pi-hole Admin interface under Settings > DNS. Clear the preset public upstream selections and leave the custom server 127.0.0.1#5053 as the upstream. Keeping a public resolver checked as an additional upstream can allow queries to bypass the encrypted proxy, so remove those entries if you require all Pi-hole upstream queries to use DoH.
5. Restart the services and verify resolution
Restart the socket, proxy service, and Pi-hole FTL daemon so they load the new configuration:
sudo systemctl restart dnscrypt-proxy.socket
sudo systemctl restart dnscrypt-proxy.service
sudo systemctl restart pihole-FTL.service
Review service status:
sudo systemctl status dnscrypt-proxy.socket
sudo systemctl status dnscrypt-proxy.service
sudo systemctl status pihole-FTL.service
Each should be active without a bind error or resolver startup failure. Test the proxy directly over its local DNS listener:
dig @127.0.0.1 -p 5053 example.com
A DNS answer indicates that the local proxy is responding. Then test Pi-hole on port 53:
dig @127.0.0.1 example.com
Check the Pi-hole Query Log or dashboard to confirm the request reached Pi-hole, and review the proxy’s journal if the test fails:
sudo journalctl -u dnscrypt-proxy.service -b --no-pager
For an extra check, look in the proxy startup or journal output for the selected resolver and a DoH protocol status. A successful dig alone proves that DNS resolution works; it does not, by itself, prove that the request used HTTPS.
Common issues and safe recovery
- “Address already in use”: another process may already occupy port 5053, or the socket override was not loaded. Check listeners with
sudo ss -lntup, review the drop-in with systemctl cat dnscrypt-proxy.socket, and confirm that the empty reset lines precede the 5053 entries.
- Proxy is active but lookups time out: check outbound HTTPS access, the resolver name, and the proxy logs. Some networks block DNS-over-HTTPS connections or restrict TCP port 443.
- Proxy test works but Pi-hole has no upstream response: confirm Pi-hole is set to exactly
127.0.0.1#5053, then restart pihole-FTL. Make sure the standard upstream checkboxes are not silently providing an alternate route.
- Ubuntu itself cannot resolve names after the change: this setup changes Pi-hole’s upstream, not the host’s
/etc/resolv.conf. Avoid replacing that file or disabling systemd-resolved as a troubleshooting shortcut.
For rollback, restore the upstream DNS setting you recorded in Pi-hole and restart pihole-FTL. Once Pi-hole no longer points to the proxy, you can disable or remove dnscrypt-proxy using the package manager. If this server also resolves its own DNS through Pi-hole, keep a local recovery path available before changing services.
Which option fits your network?
Use this single-host proxy arrangement when you want centralized DNS filtering in Pi-hole and encrypted traffic from Pi-hole to one selected resolver. It is relatively easy to inspect because the proxy has one local address and port. If you run Pi-hole in Docker, on another server, or across multiple networks, you may need a container-network address rather than loopback, and you must restrict the proxy listener so it is not exposed as an open resolver. If you need policy-based filtering, per-device identity, or encrypted DNS for roaming devices outside the home, configure those clients or a managed gateway separately; Pi-hole’s upstream DoH connection does not automatically encrypt each client’s path to Pi-hole.
Finally, remember that a router or client can bypass Pi-hole if it advertises a second DNS server. For network-wide filtering, give clients only the Pi-hole address through DHCP and account for IPv6 DNS advertisements as well as IPv4. Verify with multiple devices after changing router settings, since a correct proxy setup on the server cannot prevent a client from using another resolver directly.
Official references