Wai Hon's Blog

Split-Horizon DNS with Local DNS Rewrite

2023-05-10 #hosting

Update 2023-05-10: Thanks to @RogerBW for telling me this problem is known as “Split-horizon DNS”. As a hindsight, I was solving a known problem from scratch. Here is how:

Problem: Slow Throughput at Home

I host some services at home by mapping public domain names to my home IP. It is a typical self-hosting setup that allows me to access those services anywhere, even outside of my home. For example, I use a WebDAV service to sychronize with mobile.

However, I noticed the network throughput is very low (10~20 Mbps) when I am at home, connecting to the same local network. I would expect at least a few hundred Mbps.

Cause: Requests Routed Outside

The requests to my home server are routed outside my home’s network and come back because my service’s domain is mapped to a public IP.

Public DNS RecordTypeData
service.example.comAHome IP (e.g., 123.123.123.123)

While my ISP gives me 500M+ Mbits/sec of download, it is stint on the upload bandwidth! My local network throughout is throttled by the ISP upload speed.

I benchmark the throughput with iperf3. With a public IP, I get 21 Mbps. It matches the upload bandwidth from the ISP.

$ iperf3 -c <PUBLIC IP>
...
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.00  sec  25.6 MBytes  21.5 Mbits/sec  380             sender
[  5]   0.00-10.01  sec  25.0 MBytes  21.0 Mbits/sec                  receiver

With a private IP, I get 29 Gbps, a local throughout that looks right!

$ iperf3 -c <PRIVATE IP>
...
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.00  sec  33.5 GBytes  28.8 Gbits/sec    0             sender
[  5]   0.00-10.00  sec  33.5 GBytes  28.8 Gbits/sec                  receiver

These results match my hypothesis! The question becomes – Can I resolve the domain to a private IP when I am home?

Solution: Local DNS Rewrite

Yes! My solution is to rewrite the DNS record of my domain to a private IP with a local DNS (AdGuard Home).

Local DNS RecordTypeData
service.example.comAServer Private IP (e.g., 192.168.1.2)

It works! I can get a much higher local throughput at home using the public domain name! Also. it works seamlessly when leaving or arriving home because my phone flush its system’s DNS cache when switching network.

Alternative: Hairpin NAT

Thanks to this reply, it turns out this problem could be solved by routers with “Hairpin NAT” support (a.k.a. “NAT Loopback”). Unfortunately, mine (Google Wifi) doesn’t seem to support Hairpin NAT and I rely on a local DNS rewrite.