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
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‘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.
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.
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.
Here’s something to tinker with that may be of help:
dig @1.0.0.2 -f /home/name/queries.txt > qtime.txt
Where: /home/name/ = directory path & queries.txt (or any filename) = a pre populated list of newline separated domains & qtime.txt = the file to which the results are written. The qtime.txt file is anything you make up; it does not need to exist at all prior to your dig.
Additionally, see https://github.com/RMerl/asuswrt-merlin.ng/wiki/User-scripts for ideas on how to utilize your router’s scripting capabilities and https://forum.dd-wrt.com/wiki/index.php/Script_Execution which lists:
– /etc/config/
– /jffs/etc/config/
– /mmc/etc/config/
– /tmp/etc/config/
as the locations the router looks for any scripts (custom or otherwise) at/during specific events.
Have fun!
So are you suggesting that I could write a script that runs on the router that determines the best (lowest ping/response time, maybe?) VPN server to which it should connect? Interesting…
That’s exactly what I’m suggesting, though doing so accurately would require a (quick) connection to each server of choice. After connecting to each server on the file fed to your script, it then compares metrics and chooses the optimal server to which it then connects until required to establish a new connection, as stated in the logic of your script.
Also of note is the fact that ProtonVPN’s SecureCore .ovpn config files contain and will connect you to different IPs depending on traffic conditions. The additional security & privacy offered by both the Iceland to US & Switzerland to US secure core servers (each of which ultimately give a US-based IP) may outweigh the lesser speeds they grant. If so, using them instead of or in addition to your preferred US-based geo-servers may be of benefit. The former would ease the scripting process a bit, while the latter would simply introduce more noise, and thus privacy, into the IP addresses used.
The Linux ProtonVPN CLI is a mighty useful place to start when crafting the commands to feed your router via its scripting interface.
Lastly, if your specific router has a USB port, every command can be stored there, to be executed at designated times / events.
Thanks! I got it to work! https://collinmbarrett.com/protonvpn-dd-wrt-api-script/