Skip to content

Instantly share code, notes, and snippets.

@1999AZZAR
Last active August 26, 2026 17:59
Show Gist options
  • Select an option

  • Save 1999AZZAR/d5b9207aaa3302dc7fa9bab1fa4fb80f to your computer and use it in GitHub Desktop.

Select an option

Save 1999AZZAR/d5b9207aaa3302dc7fa9bab1fa4fb80f to your computer and use it in GitHub Desktop.
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.

UPDATE: I've built a full Web UI to automate and manage this! Check out the complete, interactive version of this setup (which now also includes a 1-click Privacy VPN mode using Unbound + DNSCrypt + WARP) here: 1999AZZAR/doh-switcher


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.

Setting Up DNS over HTTPS (DoH) Using cloudflared

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.

Table of Contents

  1. Prerequisites
  2. Step-by-Step Installation and Configuration
  3. Configure DNS Resolution
  4. Verify the Setup
  5. Optional Configuration
  6. Example DNS over HTTPS (DoH) Providers
  7. Conclusion

Prerequisites

  • A Linux-based system (Debian, Ubuntu, etc.).
  • cloudflared (Cloudflare's DoH proxy) installed.

Step-by-Step Installation and Configuration

Installation and setup

1. Download and Install cloudflared

  1. Download the latest cloudflared Debian package:

    wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
  2. Install the package:

    sudo dpkg -i cloudflared-linux-amd64.deb
    sudo apt-get install -f
  3. 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.

2. Set Up DoH Proxy

  1. Create a Dedicated Service User

    To adhere to the principle of least privilege, the cloudflared service 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 cloudflared system 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.

    1. Create the system group:

      sudo groupadd --system cloudflared
    2. 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 -r flag creates a system user and automatically generates a matching group for it in a single step.

      sudo useradd -r -s /usr/sbin/nologin cloudflared
    

    This command creates a system user cloudflared with 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.

  2. Configure the Service Create a systemd service file to run cloudflared automatically:

    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).

  3. 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
  4. Reload the systemd daemon and start the service:

    sudo systemctl daemon-reload
    sudo systemctl enable cloudflared
    sudo systemctl start cloudflared

    This reloads the systemd configuration, enables the cloudflared service to start on boot, and starts the service immediately.

3. Configure DNS Resolution

To ensure the system uses your DoH proxy for DNS resolution:

  1. Stop and Disable systemd-resolved

    The systemd-resolved service may conflict with cloudflared:

    sudo systemctl stop systemd-resolved
    sudo systemctl disable systemd-resolved
  2. Create a New /etc/resolv.conf

    Set up resolv.conf to direct DNS queries to cloudflared:

    sudo rm /etc/resolv.conf
    echo "nameserver 127.0.0.1" | sudo tee /etc/resolv.conf

    This configuration routes DNS queries through cloudflared running on localhost.

  3. 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

4. Verify the Setup

To confirm that cloudflared is working correctly:

  1. Check if cloudflared is Listening on the Correct Ports Run the following commands:

    sudo lsof -i :53

    You should see cloudflared listed as the service listening on both ports.

  2. Test DNS Resolution Use the dig command to test DNS resolution through cloudflared:

    dig @127.0.0.1 example.com

    The output should show a successful DNS query resolution.

5. (optional)

Auto-Restart on Network Changes

setup to restart the cloudflared service whenever the system connects to a new network:

  1. Install networkd-dispatcher.

    On Debian-based systems (like Ubuntu), use:

    sudo apt update
    sudo apt install networkd-dispatcher
  2. Create a Script to Restart cloudflared on 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
  3. Reload Systemd and Network Dispatcher.

    sudo systemctl daemon-reload
    sudo systemctl restart networkd-dispatcher
    sudo systemctl restart cloudflared
  4. 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

Example DNS over HTTPS (DoH) Providers

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.

DNS Provider comparison metrics

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
Google ✓✓✓ ✓✓ 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

Legend

  • 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)

Additional Provider Features

Security Features

  • Malware Blocking: Cloudflare, Quad9, NextDNS, ControlD
  • Phishing Protection: OpenDNS, AdGuard, NextDNS
  • Threat Intelligence: Quad9, NextDNS, ControlD
  • DDoS Protection: Cloudflare, Google, NextDNS

Privacy Features

  • No-Log Policy: Cloudflare, Mullvad, BlahDNS, LibreDNS
  • GDPR Compliance: All EU-based providers
  • Anonymous Statistics: NextDNS (optional), AdGuard (optional)
  • Privacy Audited: Cloudflare, Mullvad

Filtering Options

  • Ad Blocking: AdGuard, NextDNS, BlahDNS, ControlD
  • Family Filtering: OpenDNS, AdGuard, NextDNS, ControlD
  • Custom Blocklists: NextDNS, AdGuard, ControlD
  • Geographic Filtering: ControlD, NextDNS

Technical Features

  • EDNS Client Subnet: Google, OpenDNS
  • DNSSec Validation: All listed providers
  • DNS64 Support: Cloudflare, Google, NextDNS
  • ECS Support: Google, OpenDNS, PowerDNS

Provider Selection Considerations

  1. Performance Priority

    • Local users: Cloudflare, Google, NextDNS
    • Global users: Cloudflare, Google, ControlD
  2. Privacy Priority

    • Maximum privacy: Mullvad, LibreDNS, BlahDNS
    • No logging: Cloudflare, Mullvad, LibreDNS
  3. Filtering Priority

    • Ad blocking: AdGuard, NextDNS, BlahDNS
    • Family protection: OpenDNS, ControlD, NextDNS
  4. Enterprise Usage

    • Corporate environments: Google, Cloudflare, OpenDNS
    • Custom deployment: PowerDNS, OpenDNS, NextDNS

Conclusion

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.

@superclarkk

Copy link
Copy Markdown

Many thanks for doing this. It's the best guide I've seen. Is there any reason you didn't include Mullvad in your list of providers?

@1999AZZAR

Copy link
Copy Markdown
Author
  • Thank you for the great feedback! I'm glad you found the guide useful.
  • The only reason Mullvad isn't on the list is that I prefer to recommend services I have personally tested and am familiar with.
  • If you're looking for a more flexible solution, I've developed a new project called doh-switcher which makes it much easier to manage and switch between different DNS providers. You can check it out here:

https://github.com/1999AZZAR/doh-switcher

@superclarkk

Copy link
Copy Markdown

That looks really useful. Thanks - I'll take a look.

@Mrwdx8

Mrwdx8 commented Oct 4, 2025

Copy link
Copy Markdown

Hey, your instructions look perfect. It's great that you created this. I'm just wondering, can I share my DNS server with someone else so they can use it too? For example, you can add the DNS server in the app-internal app. What exactly do I need to provide? Can you help me with this? Thanks!

I was thinking something like https://dns.yourdomain.com/dns-query
Or should that DNS provider be the one I used?

@1999AZZAR

Copy link
Copy Markdown
Author

Hey @Mrwdx8, that's a great question!

Yes, it's definitely possible to share your DNS server with someone else. What you're describing is setting up your own public DNS over HTTPS (DoH) resolver. The guide in this gist is focused on setting it up for local machine use (a client), but you can adapt it to create a server.

To make https://dns.yourdomain.com/dns-query work, you'll need a few things:

  1. A Domain Name: You'll need to own yourdomain.com.
  2. A Public Server: You'll need a server with a static public IP address (like a VPS from any cloud provider).
  3. DNS Records: In your domain registrar's settings, you need to create an A record (and/or AAAA record for IPv6) for dns.yourdomain.com that points to your server's public IP address.
  4. Run cloudflared on the Server: Instead of just listening on 127.0.0.1, you would configure cloudflared on your server to accept traffic and forward it to your desired upstream DNS provider (like Cloudflare, Google, etc.).

A common and secure way to do this is to use a reverse proxy like Nginx or Caddy on your server. The reverse proxy would handle the incoming HTTPS traffic and pass it along to the cloudflared service running on the same server.

Here is a high-level overview of the steps:

  • Set up your server with a domain name pointed to it.
  • Install cloudflared on the server.
  • Install a reverse proxy like Nginx.
  • Configure Nginx to listen for requests on dns.yourdomain.com, handle the SSL/TLS certificate (you can get a free one from Let's Encrypt), and proxy the requests to the local port where cloudflared is running.
  • Configure cloudflared to run as a service, listening on a local port (e.g., 127.0.0.1:5053) and pointing to your chosen upstream DoH provider.

This setup ensures your connection is secure and allows you to share your custom DoH URL with others. Hope this helps get you started!

here a video tutorial i can fine that i think its have a good explanation to it Free Secure Self-Hosting Using Cloudflare Tunnels

@ness58

ness58 commented Aug 24, 2026

Copy link
Copy Markdown

You can also use Unbound DNS with dnscrypt-proxy for Doh servers, particularly the quad9-doh-ip4-port443-nofilter-pri server which handles HTTPS 3, and add cloudflared-warp in Traffic Only mode, and it works like the best VPN!

@1999AZZAR

1999AZZAR commented Aug 25, 2026

Copy link
Copy Markdown
Author

Hey @ness58, thanks so much for letting us know about that method! We actually loved the idea so much that we just built it into a full interactive Web UI!

We integrated your exact Privacy VPN stack (Unbound + DNSCrypt-proxy pointing to Quad9 HTTP/3 + Cloudflare WARP in Proxy/Traffic Only mode) alongside the standard Cloudflared setup, complete with a 1-click toggle to switch between them seamlessly.

Check out the completed tool here: https://github.com/1999AZZAR/doh-switcher

@ness58

ness58 commented Aug 25, 2026

Copy link
Copy Markdown

@1999AZZAR I don't use WARP in proxy mode, but in direct Traffic Only uniquely no dns mode, but if proxy mode makes dnscrypt work in dual with unbound dns, that's perfect !

@ness58

ness58 commented Aug 25, 2026

Copy link
Copy Markdown

@1999AZZAR Tell me how to install the modern web interface to manage and switch between DNS providers over HTTPS? I already have Warp, Unbound, and DNSCrypt installed; I just need the web interface.

@1999AZZAR

Copy link
Copy Markdown
Author

Hey @ness58! That makes sense regarding Traffic Only mode! Using proxy mode allows us to seamlessly bind the web traffic routing alongside our DNS resolver without blowing up the system routing tables when we toggle it on and off from the UI.

Since you already have the core tools installed, you just need to install the Web UI! You can do this by cloning the repository and running the main installer. It will set up the Python environment, configure the systemd background service, and launch the dashboard.

Just run these commands:

git clone https://github.com/1999AZZAR/doh-switcher.git
cd doh-switcher
sudo ./install.sh

This will automatically launch the web interface on http://localhost:5003 and create a handy cdns alias in your terminal to open it anytime.

(Note: The installer will check for cloudflared since the standard mode uses it as a baseline, but your existing Unbound/DNSCrypt/WARP setup will remain intact and be hooked into the Privacy VPN toggle!) Let us know how it works for you!

@ness58

ness58 commented Aug 26, 2026

Copy link
Copy Markdown

@1999AZZAR I don't use systemd-resolved, but openresolv, which is much more flexible in every respect. Oh well, I'll do without doh-switcher; thanks for trying to replace it with openresolv. Otherwise, for the Unbound configuration with dnscrypt, I advise you to let Unbound handle the cache and DNSSEC validation. Don't enable the dnscrypt cache and DNSSEC validation; Unbound handles it better. However, enable the IPv4 and IPv6 servers for optimal performance with Warp mode traffic only uniquely, no DNS. Exemple de servers optimal quad9-doh-ip4-port443-nofilter-pri et quad9-doh-ip6-port443-nofilter-pri

@1999AZZAR

Copy link
Copy Markdown
Author

Hey @ness58, thank you so much for the deep technical advice! That is incredibly helpful. We totally agree that Unbound handles the caching and DNSSEC heavy lifting much better than dnscrypt-proxy.

We have actually just updated our installation script in the repository to implement all of your optimizations—explicitly disabling cache/DNSSEC in dnscrypt-proxy, enabling the Unbound validator with optimized cache limits, and adding the dual IPv4/IPv6 Quad9 servers for maximum WARP throughput!

Regarding openresolv, totally understand sticking with what works best for your routing setup! Thanks again for sharing your expertise, it made the Privacy VPN stack significantly better for anyone who ends up using it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment