Linux Galaxy

ProtonVPN via OpenVPN

Posted on Mar 22, 2025 by kingbeowulf



Why another silly utility script?

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.

Getting Started

Proton provides instructions to manually configure both openvpn and wireguard for VPN access. This article will focus on openvpn.

Prerequisits

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
Das Script

I've placed a copy of the script in the files section. It's functional but still a bit of a work in progress.

protonvpn.sh

 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
Instructions

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
Conclusion

Comments and suggestions are welcome: kingbeowulf@linuxgalaxy.org


Return to blog

King Beowulf's Linux Adventures


Contact:

  • kingbeowulf@linuxgalaxy.org
  • mumble.linuxgalaxy.org:64738
  • Libera.chat IRC
    • ##slackware, #slackbuilds, #linuxgalaxy

Screamin' and a-streamin' !

  • https://twitch.tv/kngbwlf
  • https://www.youtube.com/@mylinuxgalaxy

Advertisement

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

Citizen Science!