DNS-over-HTTPS (DoH) encrypts your DNS queries, preventing ISPs, network administrators, and attackers from monitoring which websites you visit. While public DoH resolvers like Cloudflare and Google exist, running your own gives you complete control over your DNS privacy, ad-blocking capabilities, and query logs. In this comprehensive guide, you’ll learn how to set up your own DNS-over-HTTPS resolver using AdGuard Home.
Why Run Your Own DoH Resolver?
Privacy and Control: When you use public DNS resolvers, you’re trusting third parties with metadata about every website you visit. Running your own DoH resolver keeps this data under your control. You decide what gets logged, how long logs are retained, and who has access to them.
Centralized Ad-Blocking: AdGuard Home combines DNS-over-HTTPS encryption with powerful ad-blocking and tracker filtering. Instead of configuring ad-blockers on every device, your DoH resolver blocks ads network-wide for all connected devices — phones, tablets, smart TVs, and IoT devices.
Protection from DNS Hijacking: Many ISPs hijack DNS queries to inject ads, redirect typos to search pages, or log your browsing history. DoH encryption prevents this interference, ensuring your queries reach your resolver unmodified.
Bypass DNS-Based Censorship: Encrypted DNS prevents network-level censorship based on DNS filtering. While VPNs offer broader protection, DoH alone can bypass many simple DNS-based blocks without the performance overhead of a full VPN tunnel.
Better Performance: Running a local DoH resolver eliminates latency from remote DNS services. Queries stay on your network until they’re forwarded upstream, and AdGuard Home’s aggressive caching reduces upstream queries significantly.
Prerequisites
Before starting, you’ll need:
- A server or homelab device: Any Linux system will work. A mini PC like the Beelink SER5 Max or Intel NUC makes an excellent always-on DNS server
- Docker and Docker Compose installed: We’ll use containers for easy deployment and isolation
- A domain name: For proper TLS certificates (Let’s Encrypt requires a real domain)
- Port 443 and 53 available: DoH uses HTTPS (443), and standard DNS uses port 53
- Basic Linux command-line knowledge: You’ll be editing configuration files and running Docker commands
Understanding DNS-over-HTTPS Architecture
Before diving into configuration, let’s understand how DoH works:
Standard DNS sends queries in plaintext over UDP port 53. Anyone monitoring your network (ISP, Wi-Fi administrator, attacker) can see every domain you query. DNS responses are also unencrypted and can be spoofed.
DNS-over-HTTPS encapsulates DNS queries inside HTTPS requests. Your device sends encrypted HTTPS traffic to your DoH resolver on port 443 (or 853 for DNS-over-TLS). The queries are encrypted using TLS, making them indistinguishable from regular HTTPS traffic.
Your DoH resolver (AdGuard Home) receives these encrypted queries, decrypts them, processes them (applying filters and ad-blocking rules), then forwards them to upstream DNS servers. The responses follow the reverse path back to your client, encrypted end-to-end.
Step 1: Set Up AdGuard Home with Docker
Create a directory for your AdGuard Home configuration:
| |
Create a docker-compose.yml file:
| |
Important Port Notes:
- Port 3000 is only needed for initial setup; you can remove it after configuration
- Port 80 can be removed after setup if you only want DoH (not plain HTTP management)
- Ports 443 TCP and UDP enable both HTTPS and HTTP/3 for DoH
Start AdGuard Home:
| |
Step 2: Initial AdGuard Home Configuration
Open your browser and navigate to http://your-server-ip:3000. You’ll see the AdGuard Home setup wizard.
Setup Steps:
Choose Port: Keep the defaults (port 80 for admin panel, port 53 for DNS). We’ll configure HTTPS in the next step.
Create Admin Account: Set a strong username and password. This account has full access to DNS logs and configuration.
Configure Devices: Skip this for now — we’ll configure DoH clients later.
After completing the wizard, you’ll be redirected to the admin panel at http://your-server-ip. Log in with your credentials.
Step 3: Configure TLS Certificates for DoH
DoH requires valid TLS certificates. You have two options:
Option A: Let’s Encrypt with Certbot (Recommended)
Install Certbot on your host system:
| |
Certbot will place certificates in /etc/letsencrypt/live/dns.yourdomain.com/.
Copy certificates to your AdGuard Home directory:
| |
Certificate Renewal: Let’s Encrypt certificates expire every 90 days. Set up a cron job to renew and copy them:
| |
Add this line:
0 3 * * * certbot renew --quiet && cp /etc/letsencrypt/live/dns.yourdomain.com/*.pem /home/yourusername/adguardhome/conf/ && docker restart adguardhome
Option B: Self-Signed Certificates (Testing Only)
For testing or internal-only use, you can generate self-signed certificates:
| |
Note: Clients will show certificate warnings with self-signed certificates. This is acceptable for testing but not recommended for production.
Step 4: Enable DoH in AdGuard Home
Open AdGuard Home Admin Panel: Navigate to
http://your-server-ipGo to Settings → Encryption Settings
Configure TLS:
- Enable HTTPS: Check this box
- Server Name: Enter your domain (e.g.,
dns.yourdomain.com) - Certificate Path:
/opt/adguardhome/conf/fullchain.pem - Private Key Path:
/opt/adguardhome/conf/privkey.pem - Port HTTPS:
443
Enable DNS-over-HTTPS: The DoH endpoint will be
https://dns.yourdomain.com/dns-queryOptional - Enable DNS-over-TLS: Port
853for DoT supportClick Save
AdGuard Home will restart and begin serving DoH on port 443.
Verify DoH is Working:
| |
You should receive a JSON response with DNS data.
Step 5: Configure Upstream DNS Servers
AdGuard Home needs upstream DNS servers to forward queries. You can use encrypted upstreams for end-to-end privacy.
In AdGuard Home Admin Panel:
Go to Settings → DNS Settings
Upstream DNS Servers: Add encrypted upstreams:
https://dns.cloudflare.com/dns-query
https://dns.quad9.net/dns-query
tls://1.1.1.1
tls://9.9.9.9
- Bootstrap DNS Servers: Required to resolve DoH upstream addresses:
1.1.1.1
9.9.9.9
Test Upstreams: Click “Test upstreams” to verify connectivity
Save Configuration
Performance Tip: Use geographically close DNS servers for better latency. You can also mix DoH and DoT upstreams for redundancy.
Step 6: Configure Ad-Blocking and Filters
One major advantage of AdGuard Home is built-in ad-blocking:
Go to Filters → DNS Blocklists
Add Filter Lists: Click “Add blocklist” and add:
- AdGuard DNS filter:
https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt - AdAway:
https://adaway.org/hosts.txt - Steven Black’s Unified Hosts:
https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts - OISD Big:
https://big.oisd.nl/
- AdGuard DNS filter:
Update Filters: Click “Check for updates” to download filter lists
Configure Allowed/Blocked Services (optional): Block entire services like Facebook, TikTok, or YouTube network-wide
AdGuard Home will now block ads, trackers, and malicious domains for all DoH clients.
Step 7: Configure DoH Clients
Now configure your devices to use your DoH resolver.
Windows 10/11
Windows has native DoH support:
- Open Settings → Network & Internet → Status
- Click Properties for your active network
- Scroll to DNS server assignment and click Edit
- Select Manual
- Enable IPv4
- Preferred DNS: Enter your AdGuard Home server IP (e.g.,
192.168.1.100) - DNS over HTTPS: Select On (automatic template)
- Fallback DNS: Configure a backup server
- Click Save
Windows will automatically use DoH if your server advertises support.
macOS
macOS supports DoH via configuration profiles:
- Create a configuration profile using Apple Configurator or download a template
- Configure the DoH server URL:
https://dns.yourdomain.com/dns-query - Install the profile: System Preferences → Profiles
Alternatively, use third-party apps like DNSCrypt Proxy for easier configuration.
Linux
Install systemd-resolved (most modern distributions include it):
Edit /etc/systemd/resolved.conf:
| |
Restart systemd-resolved:
| |
For native DoH (not DoT), use dnscrypt-proxy or stubby.
Android
Android 9+ supports native DoH:
- Settings → Network & Internet → Private DNS
- Select Private DNS provider hostname
- Enter:
dns.yourdomain.com - Tap Save
Android will automatically use DoH for all DNS queries.
iOS/iPadOS
iOS 14+ supports DoH via configuration profiles:
- Create a signed
.mobileconfigprofile with your DoH server details - Install via Settings → General → Profiles
- Trust the profile
Apps like NextDNS or Cloudflare WARP simplify this process.
Browsers (Firefox, Chrome, Edge)
Most modern browsers support DoH independently:
Firefox:
- Settings → Privacy & Security → DNS over HTTPS
- Select Custom and enter:
https://dns.yourdomain.com/dns-query
Chrome/Edge:
- Settings → Privacy and security → Security
- Enable Use secure DNS
- Select Custom and enter:
https://dns.yourdomain.com/dns-query
Browser-level DoH only affects browser traffic, not system-wide queries.
Step 8: Testing Your DoH Resolver
Test DNS Resolution:
| |
Verify Ad-Blocking:
Visit http://blockads.fivefilters.org/ or query a known ad domain:
| |
You should receive a blocked/null response.
Check DNS Leak:
Visit dnsleaktest.com to verify your DoH queries aren’t leaking to your ISP’s DNS servers. You should only see your AdGuard Home server (or your chosen upstream providers, not your ISP).
Monitor Logs:
In AdGuard Home, go to Query Log to see real-time DNS queries. Verify that blocked domains show as “Blocked” and allowed domains resolve correctly.
Advanced Configuration
Enable Query Logging and Statistics
AdGuard Home provides detailed analytics:
- Settings → General Settings
- Query log retention: Set retention period (7 days, 30 days, etc.)
- Enable statistics: Track blocked queries, top clients, top domains
Privacy Note: If you’re running this for privacy, consider shorter log retention or disable logging entirely.
Configure Access Control Lists (ACLs)
Restrict which clients can use your DoH resolver:
- Settings → DNS Settings → Access Settings
- Allowed clients: Add IP ranges or individual IPs
- Disallowed clients: Block specific IPs
- Blocked domains: Additional custom blocks beyond filter lists
This prevents unauthorized users from using your DoH resolver.
Rate Limiting
Prevent abuse and DoS attacks:
- Settings → DNS Settings
- Rate limit: Set queries per second per client (default: 20)
DNSSEC Validation
Enable DNSSEC to verify DNS response authenticity:
- Settings → DNS Settings
- Enable DNSSEC: Check this box
DNSSEC adds cryptographic signatures to DNS responses, preventing tampering.
Conditional Forwarding (Split DNS)
Send specific domains to different DNS servers:
- Settings → DNS Settings → Upstream DNS servers
- Add domain-specific upstreams:
[/local.domain/]192.168.1.1
[/internal.company.com/]10.0.0.1
This is useful for resolving internal domains through your local DNS server while using DoH for external queries.
Troubleshooting Common Issues
Certificate Errors: If clients report certificate errors, verify:
- Your domain’s DNS A record points to your server’s IP
- Certificates are valid:
openssl x509 -in fullchain.pem -text -noout - The server name in AdGuard Home matches your certificate’s Common Name (CN)
Port 53 Conflicts: If port 53 is already in use (by systemd-resolved or dnsmasq):
- Stop conflicting service:
sudo systemctl stop systemd-resolved - Or configure AdGuard Home to use a different port (then configure clients accordingly)
DoH Not Working: Check firewall rules:
| |
Slow Queries: If DNS resolution is slow:
- Add more upstream servers for redundancy
- Enable parallel upstream queries in AdGuard Home settings
- Reduce filter list count (too many lists can slow processing)
IPv6 Issues: If you’re not using IPv6, disable it in AdGuard Home:
- Settings → DNS Settings → DNS server configuration
- Uncheck Enable IPv6
Security Best Practices
Use Strong Authentication: Your AdGuard Home admin panel controls your entire DNS infrastructure. Use a strong password and consider IP-based access restrictions.
Keep AdGuard Home Updated: Run docker compose pull && docker compose up -d regularly to get security patches.
Harden Your Server: If your DoH resolver is publicly accessible:
- Enable a firewall (UFW, iptables)
- Use Fail2Ban to block brute-force attempts on HTTPS
- Disable password authentication for SSH
- Keep your OS updated
Monitor Logs: Regularly review query logs for unusual activity (sudden spikes, suspicious domains, unauthorized clients).
Backup Configuration: AdGuard Home stores configuration in ~/adguardhome/conf/AdGuardHome.yaml. Back this up regularly:
| |
Performance Optimization
Increase Cache Size: AdGuard Home caches DNS responses. Increase cache size for better performance:
Edit ~/adguardhome/conf/AdGuardHome.yaml:
| |
Restart AdGuard Home after editing:
| |
Use Local Upstream Resolvers: If you run Unbound or another recursive resolver locally, use it as an upstream to eliminate external dependencies:
127.0.0.1:5335
Enable HTTP/3: AdGuard Home supports HTTP/3 (QUIC) for DoH, which offers better performance over unreliable connections. It’s automatically enabled when you expose port 443/UDP.
Conclusion
You now have a fully functional DNS-over-HTTPS resolver with ad-blocking, query logging, and complete privacy control. Your DNS queries are encrypted end-to-end, protected from ISP snooping, DNS hijacking, and network-based censorship.
Unlike public DoH services, you control your data. You decide what gets blocked, what gets logged, and who has access. Combined with AdGuard Home’s powerful filtering capabilities, you’ve built a privacy-focused DNS infrastructure that protects all devices on your network.
Next Steps:
- Configure all your devices to use your DoH resolver
- Fine-tune filter lists based on your browsing habits
- Set up automated backups of your configuration
- Consider running a secondary AdGuard Home instance for redundancy
- Explore integrating with Home Assistant or other home automation systems for conditional DNS filtering
Your self-hosted DoH resolver puts you back in control of one of the internet’s most fundamental protocols — and that’s something worth protecting.