M. Rincón Guided by asteriks

Making ProtonVPN Usable on Linux

2023-02-21 Revised: 2024-03-02

ProtonVPN provides a GUI and a console application for Linux, but on 2023, it is nearly unusable. It consumes up to 2 GB of memory idled, drops connections, and fails to reconnect unless the kill switch is deleted using nmcli. The command line application has a bizarre dependency on nm-applet, which of course means it cannot be used on a headless machine. It appears that ProtonVPN is not going to fix this. The solution is to use ProtonVPN with Wireguard.

First, install Wireguard and ufw. Then, log into ProtonVPN, and in the download section, get a few Wireguard configuration files. Add them to the NetworkManager. By default, all new wireguard connections will auto connect on start up. Since I only want one default connection, I modified all but one. In addition, I disabled IPv6 on all the connection.

nmcli con import type wireguard file <connection.conf>
nmcli con modify <connection> ipv6.method "ignore"
# if not the default connection:
nmcli con mod <connection> connection.autoconnect no
nmcli con down <connection>
nmcli -f name,autoconnect connection

I also wanted a killswitch, so I used ufw to configure one (Fedora comes with FirewallD, but I'm familiar with ufw). First I disabled connections outside my LAN. Because I want to be able to reconnect without turning off the firewall, I made exceptions for the VPN connections by allowing paths to the end points in the configuration files.

# ignore the 127.0.0.1/8 range, that's the loop back
ip address | grep inet

ufw reset
ufw default deny outgoing
ufw default deny incoming
# whitelist the range found with ip address
ufw allow in to <range start/end>
ufw allow out to<range start/end>
ufw allow out to <ip> port <port number> proto udp
ufw allow out on <connection> from any to any
ufw enable

At this point there shouldn't be any connection outside the LAN unless I have a VPN connections.

# ping google should fail
ping 8.8.8.8
# but work after vpn is activate
nmcli --ask con up <vpn name>
ping google
# we can also check for leaks
curl https://ipleak.net/json/ | jq
# and in the DNS
session=$(echo mrfox | sha1sum)
for i in $(seq 5000 5003);
do
   curl "https://${session:0:40}-${i}.ipleak.net/dnsdetection/"
   sleep 1
done

If all works as expected, ufw can be set as a service.

# If active, disable firewalld
systemctl disable --now firewalld.service
systemctl enable --now ufw.service
ufw status
# To see what was blocked
journalctl -t kernel -fag "UFW BLOCK"