Posted on Mar 22, 2025 by kingbeowulf
Proton provides and officially recommends graphical desktop utility to access their VPN services. Unfortunately, these are supported on just a few "official" Linux distributions. Proton deprecated their bash command line (CLI) version. There is a community CLI version available, written in python, but both of these will be defunct after Proton upgrades their openvpn infrastructure on 31 March 2025.
Therefore, instead of trying get there official client to work (why no offline installer, or simple tar.gz etc archive?), we created our own simple, manual bash script targeting the freely available VPN servers. Thanks goes to a fellowPortland Linux User Group member for script improvements, suggestions and testing.
Proton provides instructions to manually configure both openvpn and wireguard for VPN access. This article will focus on openvpn.
For this example, since for my Linux configuration, I will need to log in as 'root' user, I created directories under /root for the required files.
Log into your Proton account and download the .ovpn configurations. Also copy the openvpn user name and password you will require into a file, one per line, to 'protonvpn_auth.txt'.
Next, download the 'update-resolv-conf' script, copy to /etc/openvpn and set it to executable. This script will update your /etc/resolv.conf for the vpn tunnel.
If not already done, make sure that the lines
1script-security 2 2up /etc/openvpn/update-resolv-conf 3down /etc/openvpn/update-resolv-conf
are placed in the .ovpn files so that this resolv script will be executed. Your /root folder should now contain the following tree, for example:
1network 2├── protonvpn 3│ ├── jp-free-1.protonvpn.udp.ovpn 4│ ├── jp-free-16.protonvpn.udp.ovpn 5│ ├── jp-free-2.protonvpn.udp.ovpn 6│ ├── jp-free-4.protonvpn.udp.ovpn 7│ ├── jp-free-5.protonvpn.udp.ovpn 8│ ├── nl-free-1.protonvpn.udp.ovpn 9│ ├── nl-free-12.protonvpn.udp.ovpn 10│ ├── nl-free-2.protonvpn.udp.ovpn 11│ ├── nl-free-90.protonvpn.udp.ovpn 12│ ├── protonvpn_auth.txt 13│ ├── us-free-1.protonvpn.udp.ovpn 14│ ├── us-free-2.protonvpn.udp.ovpn 15│ ├── us-free-3.protonvpn.udp.ovpn 16│ ├── us-free-4.protonvpn.udp.ovpn 17│ └── us-free-5.protonvpn.udp.ovpn 18├── protonvpn.sh
I've placed a copy of the script in the files section. It's functional but still a bit of a work in progress.
1#!/usr/bin/bash 2 3set -e 4 5RED="\033[0;31m" 6GREEN="\033[0;32m" 7NC='\033[0m' # No Color 8 9VPN_PATH="/root/network/protonvpn" 10AUTH_FILE="$VPN_PATH/protonvpn_auth.txt" 11 12if [ "$EUID" -ne 0 ] ; then 13 echo "Please run $0 with root permissions" 14 exit 1 15fi 16 17# Get exit node country and index parameters and assmebly openvpn configuration name. 18ctry=$(echo $1 | tr -d "0-9") 19cfg=$(echo $1 | tr -d -c "[0-9]") 20VPN="${VPN_PATH}/${ctry}-free-${cfg}.protonvpn.udp.ovpn" 21if [ ! -e $VPN ] ; then 22 echo "VPN configuration file $1 does not exist" 23 exit 2 24fi 25 26CMD=$2 27 28echo "VPN: $VPN" 29 30# Start up protonvpn via openvpn 31start() { 32 33 # disable ipv6 34 /sbin/sysctl -w net.ipv6.conf.all.disable_ipv6=1 35 /sbin/sysctl -w net.ipv6.conf.default.disable_ipv6=1 36 /sbin/sysctl -w net.ipv6.conf.lo.disable_ipv6=1 37 38 echo -e "${GREEN}Launching $VPN...${NC}" 39 openvpn --config $VPN --auth-user-pass $AUTH_FILE --auth-nocache --mute-replay-warnings & >/dev/null 2>&1 40 RETVAL=$? 41 echo 42 return $RETVAL 43} 44 45# Make it stop! 46stop() { 47 echo -e "${GREEN}Stopping $VPN...${NC}" 48 pid=$(ps -A | grep openvpn | awk '{ print $1 }') 49 kill $pid > /dev/null 2>&1 50 RETVAL=$? 51 echo 52 /sbin/sysctl -w net.ipv6.conf.all.disable_ipv6=0 53 /sbin/sysctl -w net.ipv6.conf.default.disable_ipv6=0 54 /sbin/sysctl -w net.ipv6.conf.lo.disable_ipv6=0 55 56 echo 57 return $RETVAL 58} 59status() { 60 sz=$(/sbin/ifconfig | wc -l) 61 cz=$(/sbin/ifconfig | grep -n tun0 | cut -f1 -d":") 62 if [ -z $cz ] ; then cz=$sz; fi 63 lst=$(expr $sz \- $cz + 1) 64 ifconfig | tail -$lst 65} 66 67case "$CMD" in 68 start) 69 start 70 echo $RETVAL 71 ;; 72 stop) 73 stop 74 if [ $RETVAL ]; then 75 echo -e "Stopped ${GREEN}OK${NC}" 76 else 77 echo -e "Stopped: ${GREEN}Failed${NC}" 78 fi 79 ;; 80 restart) 81 stop 82 sleep 2 83 start 84 ;; 85 status) 86 status 87 ;; 88 *) 89 echo "Usage: bash $0 jp#|nl#|us# start|stop|status|restart" 90 exit 1 91esac
Simply open a command shell and login in as root. Then provide the script with the .ovpn country:
1root@frodo:~# cd network 2root@frodo:~/network# ./protonvpn.sh us1 start 3VPN: /root/network/protonvpn/us-free-1.protonvpn.udp.ovpn 4net.ipv6.conf.all.disable_ipv6 = 1 5net.ipv6.conf.default.disable_ipv6 = 1 6net.ipv6.conf.lo.disable_ipv6 = 1 7Launching /root/network/protonvpn/us-free-1.protonvpn.udp.ovpn... 8 90 10root@frodo:~/network# 2025-03-21 18:59:17 OpenVPN 2.5.5 x86_64-slackware-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [MH/PKTINFO] [AEAD] built on Dec 15 2021 112025-03-21 18:59:17 library versions: OpenSSL 1.1.1zb 16 Oct 2024, LZO 2.10 122025-03-21 18:59:17 NOTE: the current --script-security setting may allow this configuration to call user-defined scripts 132025-03-21 18:59:17 TCP/UDP: Preserving recently used remote address: [AF_INET]146.70.230.146:80 142025-03-21 18:59:17 UDP link local: (not bound) 152025-03-21 18:59:17 UDP link remote: [AF_INET]146.70.230.146:80 162025-03-21 18:59:17 WARNING: 'link-mtu' is used inconsistently, local='link-mtu 1549', remote='link-mtu 1541' 172025-03-21 18:59:17 WARNING: 'auth' is used inconsistently, local='auth [null-digest]', remote='auth SHA1' 182025-03-21 18:59:17 WARNING: 'keysize' is used inconsistently, local='keysize 256', remote='keysize 128' 192025-03-21 18:59:17 [node-us-293.protonvpn.net] Peer Connection Initiated with [AF_INET]146.70.230.146:80 202025-03-21 18:59:19 NOTE: setsockopt TCP_NODELAY=1 failed 212025-03-21 18:59:19 TUN/TAP device tun0 opened 222025-03-21 18:59:19 /usr/sbin/ip link set dev tun0 up mtu 1500 232025-03-21 18:59:19 /usr/sbin/ip link set dev tun0 up 242025-03-21 18:59:19 /usr/sbin/ip addr add dev tun0 10.96.0.53/16 252025-03-21 18:59:19 /etc/openvpn/update-resolv-conf tun0 1500 1624 10.96.0.53 255.255.0.0 init 26dhcp-option DNS 10.96.0.1 272025-03-21 18:59:19 Initialization Sequence Completed 28 29root@frodo:~/network# ./protonvpn.sh us1 status 30VPN: /root/network/protonvpn/us-free-1.protonvpn.udp.ovpn 31tun0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST> mtu 1500 32 inet 10.96.0.53 netmask 255.255.0.0 destination 10.96.0.53 33 unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 500 (UNSPEC) 34 RX packets 0 bytes 0 (0.0 B) 35 RX errors 0 dropped 0 overruns 0 frame 0 36 TX packets 0 bytes 0 (0.0 B) 37 TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 38 39wlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 40 inet 192.168.1.223 netmask 255.255.255.0 broadcast 192.168.1.255 41 ether 00:1e:52:7e:e5:1d txqueuelen 1000 (Ethernet) 42 RX packets 406210 bytes 476574687 (454.4 MiB) 43 RX errors 0 dropped 0 overruns 0 frame 0 44 TX packets 137286 bytes 13136167 (12.5 MiB) 45 TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 46 47root@frodo:~/network# ./protonvpn.sh us1 stop 48VPN: /root/network/protonvpn/us-free-1.protonvpn.udp.ovpn 49Stopping /root/network/protonvpn/us-free-1.protonvpn.udp.ovpn... 50 512025-03-21 19:04:32 event_wait : Interrupted system call (code=4) 522025-03-21 19:04:32 SIGTERM received, sending exit notification to peer 53net.ipv6.conf.all.disable_ipv6 = 0 54net.ipv6.conf.default.disable_ipv6 = 0 55net.ipv6.conf.lo.disable_ipv6 = 0 56 57Stopped OK 58root@frodo:~/network# 2025-03-21 19:04:33 /usr/sbin/ip addr del dev tun0 10.96.0.53/16 592025-03-21 19:04:33 /etc/openvpn/update-resolv-conf tun0 1500 1624 10.96.0.53 255.255.0.0 init 602025-03-21 19:04:33 SIGTERM[soft,exit-with-notification] received, process exiting
Comments and suggestions are welcome: kingbeowulf@linuxgalaxy.org
Contact:
Try a nice upgrade from EVGA and get a discount!
Tired of Steam, Epic and other rip-off game "stores"? Check out Humble Bundle for your digital download needs! A portion of your hard-earned gaming cash goes to charity.
King Beowulf's Humble Bundle Referral Code