Skip to content

Instantly share code, notes, and snippets.

@1999AZZAR
Last active November 16, 2025 15:07
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.

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.

@1999AZZAR
Copy link
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

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

@Mrwdx8
Copy link

Mrwdx8 commented Oct 4, 2025

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

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