Optimizing ProtonVPN Server Selection by DD-WRT with DNS
Disclaimer: I imported this post from WordPress to Jekyll on 9/2/23. Forgive the misformatting until I get a chance to clean it up.
Update 6.6.2020:
While this solution still works, I now use a new shell script to optimize server selection based on current load. See
here.
I have been a long-time user of virtual private networks for personal privacy. It is not a silver bullet, but at the
very least it makes it just a bit harder for ISPs, government agencies, and all of the sites we visit daily to profile
and surveil my family.
ProtonVPN has worked very well for me for the past couple of years. Since I use
ProtonMail, it makes sense to use their VPN as a bundled offering. ProtonVPN is also maybe
the only reputable provider offering a free tier which is a trait I like to support for those who cannot pay for premium
access.
Choosing a server to connect to via DD-WRT on our router is a bit of
a challenge, however. This is how I have sought to optimize that choice for greater uptime, reduced latency, and
automatic failover.
Selecting a Server
[](/assets/img/protonVpnConfigs_collinmbarrett.jpg)
The ProtonVPN configuration download portal
ProtonVPN has hundreds of servers classified by type (Secure Core, Tor, regular), class (basic or premium), and
location. For users who connect to the VPN through applications on their devices, selecting which server to connect to
is simple and easy to change through the polished UI. We can even see an estimate of the current load on each server so
we can select one likely to be more performant.
[DD-WRT](https://dd-wrt.com/)‘s OpenVPN client requires either an IP address or a URL to which it will connect. For
example, we can specify the IP address of their server named “US-TX#3” to connect to a specific premium server in Texas,
or we can specify “`us.protonvpn.com`” to connect to any server based in the U.S. Whichever server or URL we select is
sticky because it applies to our entire household and logging on to the router's admin panel to change it is not
frictionless.
Unfortunately, I have found that setting a single static server to connect to from our router does not hold up long-term
with any VPN provider. Servers go offline for maintenance, have traffic spikes, get temporarily blacklisted by popular
services, and offer varying levels of latency at any given time. Shuffling exit nodes might even boost our privacy as
sites we visit see us coming from different IP addresses rather than the same one all of the time. Since I do not want
to manually log on to my router often to swap out IP addresses, I would prefer to just connect to something like
“`us.protonvpn.com`” and have ProtonVPN select a quality server for me.
That US URL, however, includes all servers in the US. Ideally, I would like to filter out the basic/free servers (more
heavily loaded) and the servers in cities that are far away from my location (higher latency).
## Targeting Optimal Servers via DNS
It does not seem like ProtonVPN has plans to provide more granular URLs that target all servers in a specific city or
only premium servers (or combinations of the two). So far, it seems they are limiting options to only country-based URLs
or server-specific IP addresses.
[](/assets/img/protonVpnCloudflareDns_collinmbarrett.jpg)
Cloudflare DNS records
Since I live in Memphis, the geographically closest city with ProtonVPN servers is Atlanta. So, I collected the IP
addresses of all of the premium servers in Atlanta (9 at the time of publishing) and created DNS A records for the same
subdomain on a domain I own at my DNS provider (Cloudflare). In DD-WRT, I have then configured the OpenVPN client
connection to this new custom URL. Every time the client connects, Cloudflare DNS serves it a different IP address via
[round-robin](https://www.cloudflare.com/learning/dns/glossary/round-robin-dns/).
DD-WRT provides a watchdog feature that is handy for addressing when a VPN server goes down. Every 300 seconds, DD-WRT
pings the ProtonVPN DNS server (only accessible via a ProtonVPN connection). If that ping fails, the router reboots
itself automatically. After that reboot, the OpenVPN client requests a new server IP address from DNS. We also have the
router configured to reboot automatically every night to refresh its connection and keep shuffling the ProtonVPN exit
node to which we are connected. During that downtime, we have a firewall configured on the router so that WAN
connections are blocked until the tunnel is re-established after the power cycle.
This solution has worked well for us for several months. We have the cheapest Xfinity connection and can stream a fair
bit of video and maintain work teleconferences without any issues.
## Next Steps
It would be nice if DNS would serve up the IP address of the server with the lowest current load or with the lowest
latency, rather than merely the next up in the round-robin rotation. Doing this would require standing up some kind of
custom DNS server with the capability to measure and decide which server meets that criteria. This is probably something
I would never invest the time in building unless there is an off-the-shelf tool that could do it?
Similarly, it would be great if DD-WRT could automatically detect when latency drops below a specified threshold at
which point it cycles to another IP address. I am not sure of any way of accomplishing this either, at the moment.