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"