When you use a VPN, your internet traffic is encrypted and routed through the VPN server, hiding your browsing activity from your ISP. However, even with a VPN, your DNS requests can still leak information about your browsing habits. DNS over HTTPS (DoH) adds an additional layer of privacy by encrypting your DNS queries, making it impossible for anyone—including your VPN provider—to see what domains you’re accessing.
In this guide, we’ll explore how to configure DNS over HTTPS inside a VPN tunnel, why it matters, and the various methods to implement it across different platforms and VPN protocols.
Understanding DNS Leaks and Why DoH Inside VPN Matters
What is a DNS Leak?
Every time you visit a website, your computer needs to translate the human-readable domain name (like example.com) into an IP address. This process is called DNS (Domain Name System) resolution. By default, your computer sends these DNS queries to your ISP’s DNS servers, which can log every website you visit.
When you connect to a VPN, ideally all your traffic—including DNS queries—should go through the encrypted VPN tunnel. However, due to misconfigurations or IPv6 compatibility issues, DNS queries can sometimes “leak” outside the VPN tunnel, exposing your browsing activity to your ISP or other observers.
Why Combine DoH with VPN?
DNS over HTTPS encrypts your DNS queries using HTTPS protocol, making them indistinguishable from regular web traffic. When you combine DoH with a VPN:
- Double Encryption: Your DNS queries are encrypted twice—once by the VPN tunnel and again by HTTPS
- ISP Privacy: Your ISP cannot see even the domains you’re accessing
- VPN Provider Privacy: Your VPN provider cannot log your DNS queries
- Bypass Local DNS Blocks: DoH can bypass local DNS-based content filtering
- Protection Against DNS Spoofing: Encrypted DNS is resistant to man-in-the-middle DNS attacks
Configuring DoH Inside Different VPN Setups
Method 1: WireGuard with DoH Stubby Configuration
WireGuard is known for its simplicity and performance. Here’s how to configure DoH with WireGuard on Linux:
Step 1: Install Required Packages
# Ubuntu/Debian
sudo apt update
sudo apt install stubby dnsmasq
# Fedora/RHEL
sudo dnf install stubby dnsmasq
Step 2: Configure Stubby for DNS over HTTPS
Edit the Stubby configuration file:
sudo nano /etc/stubby/stubby.yml
Add the following configuration:
resolution_type: GETDNS_RESOLUTION_STUB
dns_transport_list:
- GETDNS_TRANSPORT_HTTPS
tls_authentication: GETDNS_AUTHENTICATION_REQUIRED
tls_query_padding_blocksize: 128
edns_client_subnet_private: 0
round_robin_upstreams: 1
listen_addresses:
- 127.0.0.1@53530
upstream_recursive_servers:
- address_data: 1.1.1.1
tls_auth_name: "cloudflare-dns.com"
tls_pubkey_pinset:
- digest: "SHA256"
value: y/oE5kfNgrX5qYJqJVq/3L2n6WcP8jR5vN3kGmT9sM=
- address_data: 8.8.8.8
tls_auth_name: "dns.google"
tls_pubkey_pinset:
- digest: "SHA256"
value: JSMUlqH2g/3BE/h2+aSxL+jEv9IU/A9zZ5Xu2HI7RoM=
Step 3: Configure WireGuard to Use Local DNS
Edit your WireGuard configuration:
sudo nano /etc/wireguard/wg0.conf
Add or modify the DNS setting:
[Interface]
PrivateKey = <your-private-key>
Address = 10.0.0.2/24
DNS = 127.0.0.1
[Peer]
PublicKey = <server-public-key>
Endpoint = vpn.example.com:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
Step 4: Configure Dnsmasq as Local Caching Resolver
sudo nano /etc/dnsmasq.conf
Add these lines:
no-resolv
server=127.0.0.1#53530
cache-size=1000
Step 5: Restart Services
sudo systemctl restart stubby
sudo systemctl restart dnsmasq
sudo wg-quick down wg0
sudo wg-quick up wg0
Now all your DNS queries will go through DoH before being sent through the WireGuard VPN tunnel.
Method 2: OpenVPN with DoH Configuration
OpenVPN doesn’t natively support DoH, but you can chain a local DoH resolver similar to the WireGuard method.
Using dnscrypt-proxy with OpenVPN
# Install dnscrypt-proxy
sudo apt install dnscrypt-proxy
# Configure dnscrypt-proxy
sudo nano /etc/dnscrypt-proxy/dnscrypt-proxy.toml
Edit the configuration:
listen_addresses = ['127.0.0.1:53']
max_clients = 250
ipv4_servers = true
ipv6_servers = false
dnscrypt_servers = true
doh_servers = true
require_dnssec = true
require_nolog = true
disable_ipv6 = true
cache = true
cache_size = 10000
cache_min_ttl = 600
cache_max_ttl = 86400
cache_neg_ttl = 3600
Configure OpenVPN to use this DNS:
# Add to your OpenVPN client config
script-security 2
up /etc/openvpn/update-dns
down /etc/openvpn/update-dns
Create the update script:
#!/bin/bash
# /etc/openvpn/update-dns
if [ "$1" = "up" ]; then
# When VPN comes up, use local DoH resolver
echo "nameserver 127.0.0.1" > /etc/resolv.conf
chattr +i /etc/resolv.conf
elif [ "$1" = "down" ]; then
# When VPN goes down, restore original DNS
chattr -i /etc/resolv.conf
cp /etc/resolv.conf.vpn /etc/resolv.conf
fi
Method 3: Configuring DoH on Windows with VPN
Windows 11 has native DoH support, which you can configure to work with your VPN:
Step 1: Enable DoH in Windows Settings
- Open Settings → Network & Internet → Wi-Fi or Ethernet
- Click on your active network connection
- Scroll to “DNS server assignment”
- Select “Manual”
- Enable “IPv4”
- Enter a DoH-compatible DNS server:
- Cloudflare:
1.1.1.1 - Google:
8.8.8.8 - Quad9:
9.9.9.9
- Cloudflare:
- Set “Preferred DNS” and “Alternate DNS” to the same IP
- Under “Preferred DNS encryption”, select “Encrypted (DNS over HTTPS)”
- Repeat for IPv6 if desired
Step 2: Configure VPN to Use System DNS
When your VPN connects, it may override your DNS settings. To ensure your VPN uses the DoH-enabled system DNS:
- Open your VPN client’s settings
- Look for “DNS Settings” or “Network Settings”
- Disable “Use VPN provider’s DNS” or similar option
- Select “Use system DNS” or “Automatic”
Method 4: macOS DoH with VPN Tunnel
On macOS, you can use the built-in DoH support or third-party applications:
Using macOS System Preferences
# For macOS Ventura and later
# Enable DoH via Terminal
sudo networksetup -setdnsservers "Wi-Fi" 1.1.1.1 8.8.8.8
# Note: Native DoH GUI settings are in System Preferences > Network > Wi-Fi > Advanced > DNS
Using dnscrypt-proxy with macOS VPN
# Install Homebrew if not installed
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Install dnscrypt-proxy
brew install dnscrypt-proxy
# Copy and edit configuration
cp /usr/local/etc/dnscrypt-proxy/dnscrypt-proxy.toml.sample /usr/local/etc/dnscrypt-proxy/dnscrypt-proxy.toml
# Edit to use DoH servers
nano /usr/local/etc/dnscrypt-proxy/dnscrypt-proxy.toml
Configure your VPN client to use 127.0.0.1 as the DNS server.
Method 5: Router-Level Configuration
Configuring DoH at the router level protects all devices on your network:
Using OpenWrt with DoH
- Install required packages:
opkg update opkg install https-dns-proxy - Configure https-dns-proxy:
# Edit /etc/config/https-dns-proxy config https-dns-proxy option interpreter '/usr/bin/https-dns-proxy' option bootstrap_dns '1.1.1.1,8.8.8.8' option resolver_url 'https://cloudflare-dns.com/dns-query' option listen_addr '127.0.0.1' option listen_port '5053' - Add firewall rule to redirect DNS:
config redirect option name 'Redirect-DNS' option src 'lan' option proto 'udp' option src_port '53' option dest_port '5053' option target 'REDIRECT'
Verifying Your DoH Inside VPN Configuration
Test for DNS Leaks
Use these online tools to verify your configuration:
- dnsleaktest.com: Run the extended test to check which DNS servers are being used
- ipleak.net: Check for IP and DNS leaks
- browserleaks.com: privacy tests
Verify DoH is Working
To verify DoH is actually encrypting your DNS:
# On Linux, use tcpdump to monitor DNS traffic
sudo tcpdump -i any -n port 53 or port 443
# You should NOT see plaintext DNS queries on port 53
# You should see encrypted HTTPS traffic on port 443
Check Which DNS Resolution You’re Using
# Test with dig
dig +short whoami.cloudflare.com @1.1.1.1
# Check your DNS resolver
nslookup example.com
Troubleshooting Common Issues
DNS Resolution Fails After Enabling DoH
- Check that your DoH provider is reachable:
curl -v https://1.1.1.1/dns-query - Verify firewall rules allow HTTPS outbound
- Check that stubby/dnscrypt-proxy is running:
systemctl status stubby
VPN Connection Drops
- Ensure “PersistentKeepalive” is set in your VPN config
- Check that your DoH resolver has a fallback
- Verify network connectivity
DNS Conflicts with VPN Provider
- Some VPNs force their own DNS servers
- Use a local DNS forwarder (dnsmasq) to override
- Configure your VPN client to use “Use system DNS” option
Advanced: Split DNS with DoH
For more granular control, implement split DNS:
# Example: Use DoH for specific domains only
# Configure in /etc/dnsmasq.conf
server=/corporate-internal.com/1.1.1.1
server=/private-network.local/1.1.1.1
bogus-priv
Related Reading
- Encrypted DNS over HTTPS on Linux
- How to Set Up Encrypted DNS-over-HTTPS (DoH) on All Devices
- How To Configure Openwrt Guest Network With Separate Dns And
- Configure Private DNS on Android for System-Wide Tracker
- Best Vpn Protocols That Still Work Inside China After Deep P
Built by theluckystrike — More at zovo.one