I still only have one Pi 2 Model B running my tertiary DNS in case both of my docker hosts on either side of the house go down

it's only got a 100Mb interface.
AdGuard Home running on them all via Docker, with AdGuard-Sync also running on the primary to keep the secondary and Pi up to date.
That's what I'd been doing for the last year or two, until recently. I had two primary DNS servers running at home (YouFibre symmetric 2000), and was using my 3B+ as a tertiary hanging off a different switch and power, on a different floor, just in case. All our home and mobile devices are set to use DoH or DoT using the domain for those DNS servers. At home, split DNS sends them directly to the server by its LAN IP. Once a client (e.g. iPhone) moves away off-prem, it resolves to the usual DNS record for
dns.mydomain.com
.
Of course, this leaves the glaring problem that if or when your WAN goes down for whatever reason, you're screwed and nobody has Internet (DNS) whether they're at home or away. I started using a secondary AGH instance on a VPS, so that I had geo-redundancy, but this left the issue of how to split the traffic between them. In the end I found it far easier, better and more reliable to just set up a load balancer on the VPS off-prem instead, and do it that way. I
could have run the load balancer at home, of course, but that would defeat the object in case WAN went down - which is what we're mitigating in the first place! While my home connection has been very reliable, we still obviously can't compete with the uptime and reliability of a hyperscale cloud provider. So, VPS fronting the domain it is.
In case it's something you want to play with, set up a VPS with AdGuard Home running on ports 4443 and 8553 (or similar). As AGH is only running locally behind the proxy, the ports it uses doesn't matter. The usual 443/853 would, of course, conflict with the proxy listening on 443 for incoming DoH client traffic. I did it like this if you want to give it a shot (other methods are available):
1. Set the domain's DNS to the IPs of the VPS instead of your usual DNS IPs.
A dns.mydomain.com 84.x.x.1
# The VPS IP
AAAA dns.mydomain.com 2a0a:xxxx:1::123
# The VPS IPv6
CNAME *.dns.mydomain.com dns.mydomain.com
# CNAME the sub-subdomain to the primary subdomain, in case you use AGH's client identifiers (my-iphone.dns.mydomain.com)
2. Install Nginx and the stream module on your VPS. Use whatever OS you like but I'd suggest a RHEL clone, Debian or similar. Configure it to pass through conections to your backend without terminating the TLS or changing the traffic in any way. Essentialy, Nginx becomes a 'switch' just passing along traffic to whatever route(s) it's told to. We want to specify a primary DNS, then a secondary and tertiary backup. If the primary is up, it should get all the traffic, all of the time. If primary fails, Nginx should move seamlessly to the first backup and switch back to primary if/when it comes back up - and so on. The locally running AGH instance on the VPS is your last ditch safety net should your home WAN die. Your clients will still get DNS resolution from the VPS (Nginx > AGH) until your home WAN comes back up.
Code:
user nginx;
worker_processes auto;
worker_cpu_affinity auto; # TWEAK: Pin workers to CPU cores for best performance
error_log /var/log/nginx/error.log warn; # TWEAK: Reduce logging to only important warnings/errors
pid /run/nginx.pid;
# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 4096; # TWEAK: Increase connections per worker based on RAM and OS limits
multi_accept on; # TWEAK: Accept multiple connections at once for efficiency
}
# =================================================================
# == Stream Block for TCP/UDP DNS Load Balancing
# =================================================================
stream {
# Upstream group for services on port 853 (DoT)
upstream dot_backend {
# Primary Server
server 185.xxx.xxx.100:853;
server [2000:xxxx:01::100]:853;
# First Backup Server
server 185.xxx.xxx.101:853 backup;
server [2000:xxxx:01::101]:853 backup;
# Tertiary DNS (Second Backup Server - local AdGuard Home instance on the VPS itself)
server 127.0.0.1:8553 backup;
}
# Upstream group for services on port 443 (DoH)
upstream doh_backend {
# Primary Server
server 185.xxx.xxx.100:443;
server [2000:xxxx:01::100]:443;
# First Backup Server
server 185.xxx.xxx.101:443 backup;
server [2000:xxxx:01::101]:443 backup;
# Second Backup Server (local AdGuard Home instance)
server 127.0.0.1:4443 backup;
}
# Server listening for Port 853 traffic (TCP & UDP)
server {
listen 853;
listen 853 udp;
proxy_pass dot_backend;
proxy_timeout 3s;
}
# Server listening for Port 443 traffic (TCP & UDP)
server {
listen 443;
listen 443 udp;
proxy_pass doh_backend;
proxy_timeout 3s;
}
}
# =================================================================
# == HTTP Block for Exposing Status Metrics
# =================================================================
http {
# This server block is only for viewing statistics
server {
# Listen on port 8080, only accessible from the local machine for security
listen 127.0.0.1:8080;
server_name localhost;
# TWEAK: Disable unnecessary access logging for the stats page
access_log off;
location /nginx_status {
stub_status; # This directive enables the stats page
# Security: Only allow access from the local machine
allow 127.0.0.1;
deny all;
}
}
}
Clients can continue to use your AGH instances via your DNS domain. Provided all is well, they'll seamlessly be passed along to your primary AGH server at home (domain > VPS IP > Nginx > Home IP > AGH) with no perceptible delay. If primary dies, Nginx will swap to your secondary/backup server at home. If your home WAN goes down for maintenance, because of a router error or some other reason, your last ditch save will have Nginx switch down to hitting localhost:4443 and using its own AGH until your home Internet is working again. Clients will never feel or know the difference, agh-sync keeps them all reflecting the same config, and you can sleep better at night. Well, I did, anyway.
The only remaining issue is what to do with the ageing RasPi 3B+. I'm struggling to find a use-case for it now, aside from hosting dnsmasq (3MB RAM!) as a pointer to the main DNS so clients can have an extra DNS to point at. Some IoT devices will hard code 8.8.8.8 or similar if you don't use all the DNS entries in their config, so there's that I suppose. Really, it's outlived its usefulness now, and has gone through variouus iterations of FreeBSD and AlmaLinux, but I'm sure I'll find a use for it eventually...
e: Tweaked the config and added CNAME for *.dns.mydomain.com