This guide explains how to set up DNS over HTTPS (DoH) on a Linux system using cloudflared. DoH ensures that your DNS queries are encrypted and secure, protecting your online privacy and preventing third-party monitoring of your internet activity.
- Prerequisites
- Step-by-Step Installation and Configuration
- Configure DNS Resolution
- Verify the Setup
- Optional Configuration
- Example DNS over HTTPS (DoH) Providers
- Conclusion
- A Linux-based system (Debian, Ubuntu, etc.).
cloudflared(Cloudflare's DoH proxy) installed.
-
Download the latest
cloudflaredDebian package:wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
-
Install the package:
sudo dpkg -i cloudflared-linux-amd64.deb sudo apt-get install -f
-
Verify the installation:
cloudflared --version
This installs cloudflared and ensures all dependencies are met. You can verify the installation by checking the version with cloudflared --version.
-
Create a Dedicated Service User
To adhere to the principle of least privilege, the
cloudflaredservice must run as a dedicated, non-root user. This isolates the service and limits potential damage if it were ever compromised.Below are two common methods to create the required
cloudflaredsystem account. Both achieve the same secure outcome.Method A: Explicit Creation (Recommended)
This two-step process is the most explicit and universally compatible method. It first creates a dedicated group, then creates the user and assigns it to that group.
-
Create the system group:
sudo groupadd --system cloudflared
-
Create the system user:
sudo useradd --system -g cloudflared -d /var/lib/cloudflared -s /sbin/nologin cloudflared
Method B: Shortcut Command
Most modern Linux systems (like Debian, Ubuntu, and Fedora) provide a convenient shortcut. The
-rflag creates a system user and automatically generates a matching group for it in a single step.sudo useradd -r -s /usr/sbin/nologin cloudflaredThis command creates a system user
cloudflaredwith no login permissions.Both methods create a system user named cloudflared with /sbin/nologin as its shell, which prevents it from being used for interactive logins.
-
-
Configure the Service Create a systemd service file to run
cloudflaredautomatically:sudo nano /etc/systemd/system/cloudflared.service
Add the following configuration to the service file:
[Unit] Description=cloudflared DNS over HTTPS proxy After=network-online.target Wants=network-online.target StartLimitIntervalSec=60 StartLimitBurst=10 [Service] # Service execution Type=simple ExecStart=/usr/bin/cloudflared proxy-dns --port 53 --upstream <your_DoH> TimeoutStopSec=20 Restart=on-failure RestartSec=5s # User and group configuration User=cloudflared Group=cloudflared # Capability controls: Limit process abilities CapabilityBoundingSet=CAP_NET_BIND_SERVICE AmbientCapabilities=CAP_NET_BIND_SERVICE NoNewPrivileges=true # Filesystem sandboxing: Restrict file access ProtectSystem=strict ProtectHome=true PrivateTmp=true PrivateDevices=true ProtectKernelTunables=true ProtectKernelModules=true ProtectControlGroups=true # System call and resource controls: Restrict kernel interactions MemoryDenyWriteExecute=true RestrictAddressFamilies=AF_INET AF_INET6 RestrictNamespaces=true SystemCallArchitectures=native # Resource limits LimitNOFILE=1024 LimitNPROC=10 [Install] WantedBy=multi-user.target
Replace
<your_DoH>with the URL of your chosen DNS over HTTPS provider (refer to the list below). -
Grant Permission to Bind to Port 53:
On Linux, non-root processes cannot bind to ports below 1024 by default. You can use setcap to allow Cloudflared to bind to port 53 without requiring root privileges:
sudo setcap 'cap_net_bind_service=+ep' /usr/bin/cloudflared -
Reload the systemd daemon and start the service:
sudo systemctl daemon-reload sudo systemctl enable cloudflared sudo systemctl start cloudflaredThis reloads the systemd configuration, enables the
cloudflaredservice to start on boot, and starts the service immediately.
To ensure the system uses your DoH proxy for DNS resolution:
-
Stop and Disable
systemd-resolvedThe
systemd-resolvedservice may conflict withcloudflared:sudo systemctl stop systemd-resolved sudo systemctl disable systemd-resolved
-
Create a New
/etc/resolv.confSet up
resolv.confto direct DNS queries tocloudflared:sudo rm /etc/resolv.conf echo "nameserver 127.0.0.1" | sudo tee /etc/resolv.conf
This configuration routes DNS queries through
cloudflaredrunning on localhost. -
Configure Firewall:
If your system uses a firewall, allow traffic on ports 53:
sudo iptables -I INPUT -p tcp --dport 53 -j ACCEPT sudo iptables -I INPUT -p udp --dport 53 -j ACCEPT
To confirm that cloudflared is working correctly:
-
Check if
cloudflaredis Listening on the Correct Ports Run the following commands:sudo lsof -i :53
You should see
cloudflaredlisted as the service listening on both ports. -
Test DNS Resolution Use the
digcommand to test DNS resolution throughcloudflared:dig @127.0.0.1 example.com
The output should show a successful DNS query resolution.
setup to restart the cloudflared service whenever the system connects to a new network:
-
Install
networkd-dispatcher.On Debian-based systems (like Ubuntu), use:
sudo apt update sudo apt install networkd-dispatcher
-
Create a Script to Restart
cloudflaredon Network Change.You need to create a script that networkd-dispatcher will call when a new network connection is detected.
- Create the script:
sudo nano /etc/networkd-dispatcher/routable.d/restart-cloudflared.sh
- Add the following content to the script:
#!/bin/bash # Restart the cloudflared service systemctl restart cloudflared
- Make the script executable:
sudo chmod +x /etc/networkd-dispatcher/routable.d/restart-cloudflared.sh
- Create the script:
-
Reload Systemd and Network Dispatcher.
sudo systemctl daemon-reload sudo systemctl restart networkd-dispatcher sudo systemctl restart cloudflared
-
Verify the Configuration.
- Check the status of the cloudflared service:
sudo systemctl status cloudflared
- Monitor network events and check if cloudflared restarts when connecting to a new network:
journalctl -u cloudflared -f
You can choose any of the following DNS providers for your DoH setup:
| Provider | URL | IPv4 | IPv6 | Best For | Homepage | More Info | Pricing |
|---|---|---|---|---|---|---|---|
| Google Public DNS | https://dns.google/dns-query |
8.8.8.8, 8.8.4.4 |
2001:4860:4860::8888, 2001:4860:4860::8844 |
General use, fast global coverage | Google Public DNS | No filtering or blocking, focuses on speed and reliability | Free |
| Cloudflare DNS | https://cloudflare-dns.com/dns-query |
1.1.1.1, 1.0.0.1 |
2606:4700:4700::1111, 2606:4700:4700::1001 |
Privacy-focused, fast performance | Cloudflare DNS | DNS over HTTPS (DoH), DNS over TLS (DoT), strong privacy protection, supports ESNI | Free |
| AdGuard DNS | https://dns.adguard.com/dns-query |
94.140.14.14, 94.140.15.15 |
2a10:50c0::ad1:ff, 2a10:50c0::ad2:ff |
Ad-blocking, privacy protection | AdGuard DNS | Blocks ads, trackers, phishing sites, malware, and adult content, customizable filtering | Available Free (basic), Paid (premium filtering options) |
| Quad9 DNS | https://dns.quad9.net/dns-query |
9.9.9.9, 149.112.112.112 |
2620:fe::fe, 2620:fe::9 |
Security and malware protection | Quad9 DNS | Filters malicious domains, partners with security firms for threat intelligence, privacy-focused | Free |
| OpenDNS | https://doh.opendns.com/dns-query |
208.67.222.222, 208.67.220.220 |
2620:0:ccc::2, 2620:0:ccd::2 |
Parental control and security | OpenDNS | Offers family shield for content filtering, customizable filters, anti-phishing | Available Free (basic), Paid (premium with custom filtering) |
| CleanBrowsing DNS | https://doh.cleanbrowsing.org/doh/family-filter/ |
185.228.168.168, 185.228.169.168 |
2a0d:2a00:1::, 2a0d:2a00:2:: |
Family-safe, content filtering | CleanBrowsing DNS | Family and adult filters, malware blocking, customizable plans for different use cases | Available Free (basic), Paid (advanced filters) |
| NextDNS | https://dns.nextdns.io |
45.90.28.0, 45.90.30.0 |
2a07:a8c0::, 2a07:a8c1:: |
Highly customizable privacy and security | NextDNS | Fully customizable, blocks ads, trackers, malicious domains, and provides analytics | Available Free (limited queries), Paid (unlimited queries and advanced settings) |
| ControlD | https://freedns.controld.com/p0 |
76.76.2.0, 76.76.10.0 |
2606:1a40::, 2606:1a40:1:: |
Customizable filtering, blocking | ControlD | Multiple filtering modes (e.g., malware, ads, trackers), offers custom DNS profiles | Available Free (basic profiles), Paid (customizable profiles) |
| Comodo Secure DNS | https://doh.comodo.com/dns-query |
8.26.56.26, 8.20.247.20 |
Not available | Security-focused, basic filtering | Comodo Secure DNS | Focuses on blocking malware and phishing, no custom filtering | Free |
| Yandex DNS | https://dns.yandex.com/dns-query |
77.88.8.8, 77.88.8.1 |
2a02:6b8::feed:0ff, 2a02:6b8:0:1::feed:0ff |
Security, content filtering | Yandex DNS | Offers basic, safe, and family filtering options, content protection, speed-optimized | Free |
For a more comprehensive list of DNS providers, visit AdGuard DNS Providers.
The table includes a comprehensive DNS provider comparison with performance metrics, features, and official links:
| Provider | Latency | Privacy | Filtering | Logging | DNSSEC | Support | Features | DoH Endpoint | IPv4 Primary | IPv6 Primary |
|---|---|---|---|---|---|---|---|---|---|---|
| Cloudflare | ✓✓✓ | ✓✓✓ | Optional | No | Yes | 24/7 | Malware blocking, Family filter | https://dns.cloudflare.com/dns-query |
1.1.1.1 | 2606:4700:4700::1111 |
| ✓✓✓ | ✓✓ | No | Limited | Yes | Business Hours | Global load balancing | https://dns.google/dns-query |
8.8.8.8 | 2001:4860:4860::8888 | |
| Quad9 | ✓✓ | ✓✓✓ | Yes | No | Yes | 24/7 | Threat blocking, EDNS | https://dns.quad9.net/dns-query |
9.9.9.9 | 2620:fe::fe |
| AdGuard | ✓✓ | ✓✓ | Yes | Optional | Yes | Business Hours | Ad blocking, Custom filters | https://dns.adguard.com/dns-query |
94.140.14.14 | 2a10:50c0::ad1:ff |
| OpenDNS | ✓✓ | ✓✓ | Yes | Yes | Yes | 24/7 | Parental controls, Phishing protection | https://doh.opendns.com/dns-query |
208.67.222.222 | 2620:119:35::35 |
| NextDNS | ✓✓✓ | ✓✓✓ | Yes | Optional | Yes | 24/7 | Custom blocklists, Analytics | https://dns.nextdns.io |
45.90.28.0 | 2a07:a8c0:: |
| ControlD | ✓✓✓ | ✓✓✓ | Yes | No | Yes | Business Hours | Custom profiles, Geographic filters | https://freedns.controld.com/p0 |
76.76.2.0 | 2606:1a40:: |
| Mullvad | ✓✓ | ✓✓✓ | Optional | No | Yes | 24/7 | Ad blocking, No logging | https://doh.mullvad.net/dns-query |
194.242.2.2 | 2a07:e340::2 |
| BlahDNS | ✓✓ | ✓✓✓ | Yes | No | Yes | Community | Ad blocking, Privacy focused | https://doh-fi.blahdns.com/dns-query |
45.91.92.121 | 2a0e:dc0:6:23::2 |
| LibreDNS | ✓✓ | ✓✓✓ | Optional | No | Yes | Community | No filtering, Privacy focused | https://doh.libredns.gr/dns-query |
116.202.176.26 | 2a01:4f8:c17:ec67::1 |
| DuckDNS | ✓✓ | ✓✓✓ | No | No | Yes | Limited | Privacy focused | https://basic.duckdns.org/dns-query |
185.199.108.153 | 2606:4700:3037::6815:8b99 |
| Foundation for Applied Privacy | ✓✓ | ✓✓✓ | No | No | Yes | Limited | GDPR compliant | https://doh.applied-privacy.net/query |
93.177.65.183 | 2a03:4000:38:53c::2 |
| CZ.NIC ODVR | ✓✓ | ✓✓ | Optional | Limited | Yes | Business Hours | Czech Republic based | https://odvr.nic.cz/dns-query |
193.17.47.1 | 2001:148f:ffff::1 |
| DNS.SB | ✓✓ | ✓✓ | No | No | Yes | Limited | Simple, Privacy focused | https://doh.dns.sb/dns-query |
185.222.222.222 | 2a09:: |
| PowerDNS | ✓✓ | ✓✓ | Optional | Limited | Yes | Community | Self-hosted option | https://doh.powerdns.org |
Variable | Variable |
- Latency: ✓ (>100ms), ✓✓ (50-100ms), ✓✓✓ (<50ms)
- Privacy: ✓ (Basic), ✓✓ (Enhanced), ✓✓✓ (Maximum)
- Support: Community (Forum/Email), Limited (Email only), Business Hours (9-5 Support), 24/7 (Full Support)
- Malware Blocking: Cloudflare, Quad9, NextDNS, ControlD
- Phishing Protection: OpenDNS, AdGuard, NextDNS
- Threat Intelligence: Quad9, NextDNS, ControlD
- DDoS Protection: Cloudflare, Google, NextDNS
- No-Log Policy: Cloudflare, Mullvad, BlahDNS, LibreDNS
- GDPR Compliance: All EU-based providers
- Anonymous Statistics: NextDNS (optional), AdGuard (optional)
- Privacy Audited: Cloudflare, Mullvad
- Ad Blocking: AdGuard, NextDNS, BlahDNS, ControlD
- Family Filtering: OpenDNS, AdGuard, NextDNS, ControlD
- Custom Blocklists: NextDNS, AdGuard, ControlD
- Geographic Filtering: ControlD, NextDNS
- EDNS Client Subnet: Google, OpenDNS
- DNSSec Validation: All listed providers
- DNS64 Support: Cloudflare, Google, NextDNS
- ECS Support: Google, OpenDNS, PowerDNS
-
Performance Priority
- Local users: Cloudflare, Google, NextDNS
- Global users: Cloudflare, Google, ControlD
-
Privacy Priority
- Maximum privacy: Mullvad, LibreDNS, BlahDNS
- No logging: Cloudflare, Mullvad, LibreDNS
-
Filtering Priority
- Ad blocking: AdGuard, NextDNS, BlahDNS
- Family protection: OpenDNS, ControlD, NextDNS
-
Enterprise Usage
- Corporate environments: Google, Cloudflare, OpenDNS
- Custom deployment: PowerDNS, OpenDNS, NextDNS
This guide provides a detailed method to set up DNS over HTTPS on your Linux machine using cloudflared, ensuring your DNS queries are encrypted and secure. Select a DNS provider from the examples above or from the AdGuard DNS Providers list to complete your setup.
That looks really useful. Thanks - I'll take a look.