I no longer rely on my router’s DNS service after I started using Unbound on my home network. After setting up split-horizon DNS for internal subnets at home, I used public DNS servers for the outbound traffic. That meant several services, and an ISP could easily peek into my DNS activities. But I wanted to keep my DNS traffic more private and reliable.
For that, I needed to encrypt the DNS traffic while still using Unbound as a recursive resolver. I considered WireGuard as a VPN to put Unbound DNS traffic behind it. Using a third-party VPN wouldn’t solve anything. My browsing activities, including my DNS traffic, would be easily viewable or logged by a third-party VPN provider. Here’s how I managed to encrypt my DNS and use Unbound as a recursive DNS resolver, enjoying the best of both worlds.
Setting up a recursive resolver and encrypting DNS traffic
Make it all happen locally
I used Unbound as a recursive resolver with Pi-Hole on my home network. When I couldn’t keep up with the changes in Pi-Hole v6, I bid it adieu. While the third-party public DNS seemed faster than the ISP-provided ones, the privacy and DNS traffic logging aspect always concerned me. So, I deployed and configured Unbound as a recursive resolver for my home network within a Debian VM on Proxmox. It involved configuring Unbound to listen to the Debian VM’s IP address (192.168.1.7) and setting the access control for the entire network (192.168.1.0/24).
Next, I installed a WireGuard configuration on the same Debian VM to work as a VPN and encrypt all traffic, including the DNS. That way, my ISP or any service sniffing around would only find a fully encrypted WireGuard connection. Configuring WireGuard required more work since I needed to create a public and private key on every device I wanted to use. The public keys of those devices need to appear under the Peers section of the WireGuard (wg0) instance file, and that took quite a while to double-check.
In retrospect, I could've easily used wg-easy container for the WireGuard setup. However, I didn't want to run yet another container and sought a reliable and stable WireGuard setup.
In the Interface section, I set the address to 10.10.10.2/24 as my WireGuard IP on the Debian VM. Under the Peers section, I used 0.0.0.0/0 as the Allowed IPs parameter to make WireGuard route all IPv4 addresses from my client (Debian VM) for a full tunnel VPN setup.
The flip side of most home networks is the dynamic public IP address the ISP supplies and changes frequently. Hence, I couldn’t define it in the wg0 instance. As an alternative, I considered using a Dynamic DNS service provider, such as DuckDNS, No-IP, or DynDNS, to poll the dynamic public IP address of my home network. All I needed to do was set the DDNS URL as an Endpoint in the WireGuard configuration. However, I chose another option.
Extending the setup to become remote access-capable
Requires a VPS to reach your home network
I anchored my VPS for more flexibility and reliability, especially with its static IP. A VPS costs roughly $3 to $5 per month, depending on the service provider you choose. Using a VPS requires a slightly more advanced understanding of computing and networking. Besides hiding my home network IP address from the public, the static IP address from the VPS allows all inbound traffic that my ISP might be blocking, and I also enjoy reliable remote access.
I repeated the Unbound and WireGuard installation on the VPS. In contrast, Unbound’s recursive configuration was relatively similar. The only hiccup was the root.hints file, which I solved by assigning ownership to Unbound.
Meanwhile, setting up WireGuard’s configuration requires extra effort. I had to use my Debian VM’s public key in the VP’s WireGuard configuration and vice versa. It took me a few tries to get those keys right. Under the Interface section, I used 10.10.10.1/24 as the address and the AllowedIPs to 10.10.10.2/32 (for routing through a single device only). After setting up WireGuard on my VPS and home network, I ran the wg show command to check if a handshake had occurred between the two instances.
For internet and cross-device access, I had to ensure that the IP forwarding was enabled and verify the iptables NAT rules to confirm that masquerading (sudo iptables -t nat -A POSTROUTING -s ) is in place. When it wasn’t working, I couldn’t access the internet from the machines running the WireGuard server.
Configuring a fallback option when home DNS is unreachable
Prevent any leaks to third-party DNS
While I prefer using Unbound locally, I deployed it on my VPS as a redundant, failover DNS option. So when my home network’s Unbound fails to respond, the one on the VPS steps in as a fallback to route all the queries. That way, DNS continues to work when I am on the move or using a mobile phone with mobile data. On the VPS, I defined a forward zone in Unbound’s recursive.conf file to point to the localhost and WireGuard IP address of the home network. It helps my mobile devices stay connected even when my home network is unreachable.
Building a seamless, powerful, and privacy-centric setup
Unbound provides a solid recursive DNS resolver, and I could encrypt the traffic by putting it behind a WireGuard VPN. To solve DHCP issues, I merely restarted the ISP’s modem and my router. Using a VPS to encrypt Unbound DNS traffic gives me peace of mind when accessing specific files and self-hosted apps on my home network from anywhere. Sure, it’s a little more tedious to set up than using Tailscale. However, I get to enjoy privacy and control, despite having to configure WireGuard on every device I intend to use it on. Looking back, I am guilty of the snafu with Firewall rules, and I am learning to improve with OPNsense.
