Update (2018-Sep-18): since I wrote this post in 2016, PIA has started offering a very similar script (here) that can be used to configure their VPN on Fedora. Although I try to keep this post up to date (still works up to Fedora 28!), you might want to use that one instead.
Private Internet Access VPN provider offers its client software for many platforms, but Linux. There is however a guide that describes how to configure PIA VPN servers only for Ubuntu. If you use Fedora then you may find this post useful (this was tested on a Fedora 23 Workstation).
Preparation
First of all you must be root before you can execute the following steps. To become root you just need to open up a terminal and type the following command:
$ su -
You will then be asked for the root’s password.
Your computer needs to be connected to the Internet. These steps also assume that certain software is already installed on your computer. Although this software is pretty standard in any modern Linux distribution it’s always better to be sure, open a terminal and execute the following command:
# dnf -y install wget unzip python NetworkManager-openvpn-gnome util-linux coreutils
NOTE: if you’re using an older version of Fedora or any other Red Hat based Linux distribution (e.g. CentOS, Scientific Linux or Oracle Linux) then you might need to replace dnf
by yum
and the package names might be slightly different.
Have your PIA VPN username handy (the one that starts with a “p” followed by some digits).
Configuring PIA VPN
I put together the following shell script to make this process easier. Copy all the following lines, paste them into your favorite text editor and save it as a pure text file (a.k.a. ASCII file).
#!/bin/bash # Get username echo -n "Enter your PIA VPN username: " read PIAUSR # Download servers info wget -q -O - https://privateinternetaccess.com/vpninfo/servers?version=24 | head -1 > /tmp/servers-$$.json # Parse servers info cat /tmp/servers-$$.json | python -c '\ import json,sys;\ d = json.load(sys.stdin);\ print "\n".join([d[k]["name"]+":"+d[k]["dns"] for k in d.keys() if k != "info"])' > /tmp/servers-$$.txt # Install PIA CA's certificate wget -q -O /tmp/openvpn-$$.zip https://www.privateinternetaccess.com/openvpn/openvpn.zip unzip -pa /tmp/openvpn-$$.zip ca.rsa.2048.crt > /etc/openvpn/pia_ca.crt # Write config files rm -f /etc/NetworkManager/system-connections/PIA\ -\ * while read server; do name="PIA - `echo $server | cut -d: -f1`" cat << EOF > "/etc/NetworkManager/system-connections/$name" [connection] id=$name uuid=`uuidgen` type=vpn autoconnect=false [vpn] service-type=org.freedesktop.NetworkManager.openvpn username=$PIAUSR dev=tun comp-lzo=no remote=`echo $server | cut -d: -f2` port=1198 cipher=AES-128-CBC reneg-seconds=0 connection-type=password password-flags=1 ca=/etc/openvpn/pia_ca.crt remote-cert-tls=server [ipv4] method=auto EOF chmod 600 "/etc/NetworkManager/system-connections/$name" done < /tmp/servers-$$.txt # Tidy up rm /tmp/servers-$$.json /tmp/servers-$$.txt /tmp/openvpn-$$.zip echo Done
NOTE: the script above is also available on GitHub.
Once you have saved this shell script into a text file, certify that you can execute it. Assuming that you’ve saved this script into a file called pia.sh
then you can do that by running the following command on a terminal:
# chmod a+x pia.sh
Please note that by no means this shell script should be taken as a model. It was developed to be small and to run once. There are many things that should be improved to make this a production class script, like handling software dependencies, checking return codes and issuing proper error messages, making sure the PATH is correctly defined, cleaning up and validating any input from the user, verifying the integrity of objects downloaded from the Internet, trapping signals, adding proper comments, etc.
Ok, now it’s time to run it! On a terminal, execute:
# ./pia.sh
When asked, enter your PIA VPN username. After a few seconds you should see “Done”. Yay!
Making SELinux happy
This configuration process has created new files on your system, therefore, in order to leave everything in order, you need to fix the security context of these files according to SELinux policy. To do that just run the following commands:
# restorecon -F /etc/openvpn/pia_ca.crt # restorecon -F /etc/NetworkManager/system-connections/PIA\ *
Validation
If you didn’t see any error messages then it’s time to check if all PIA VPN servers were indeed configured:
# ls /etc/NetworkManager/system-connections/PIA\ *
You should see dozens of servers/locations. Now restart NetworkManager and enjoy it!
# systemctl restart NetworkManager
Leave a comment below if you liked this article or, if you didn’t, please tell me how I can make it better.
Awesome little piece of code Felix. Works like a charm. Thanks!
Works flawlessly on fedora 27.
Just needed to change the version for the list of servers fetched in the script (as of today the version is 79) and done.
Thank you !
I can confirm this works with CentOS 7, just replaced dnf with yum and had to enable the epel repository. Thanks!
Works on Fedora 27 too !!! Great job!!!
I owe you a beer, sir. Thank you so much!
Thanks for this! Works great on a Fedora 25 system.
Can also confirm this works like a charm on Fedora 25 as well.
buen trabajo, mi fedora 23 y yo te agradecemos
Great, this had me stumped but it all works fine.
One question, in Windows and in Mint, their is also an option to go into ‘Settings’ and select to use MACE and othe PIA specific settings, I am uncertain how to do this. Do you know?
Thanks a lot for this it really helped.
I believe you are referring to the PIA client app on Windows and Mint.
MACE is an ad blocker developed by PIA and released earlier this year that uses a custom DNS server to resolve IP addresses to localhost whenever it detects a unwanted domain.
You might do just fine with browser extensions like Privacy Badger or Ghostery though.
Thanks for the reply – no I mean when you right click on the PIA icon in the taskbar (in mint) as well as the aption of connecting to any of the servers in the server list, their as also a ‘settings’ choice that can be made. This is what I was trying to get into.
I’m already using Privay Badger an d uBlock.
Thanks again.
Thank you very much, im lazy and didn’t want to do this manually lol.
NICE WORK!! seemless! Thanks
Thank you so much for taking the time to do this! You provided an awesome guide for running the script and I really appreciate it 🙂
Thanks alot for taking the time to post this article. I was a little overwhelmed having jumped into the deep end from Linux Mint after a couple of years into Fedora and your explanation helped me painlessly set up PIA on my new system.
Much Appreciated
PIA must have did something on their end as my VPN on fedora does not work anymore. Connection cannot be activated.
Was working before today, last night… 🙂
Can this script be updated to reflect any changes? Is there a removal script for the old setup?
Two days ago PIA sent out an email to all clients communicating that they are no longer doing business within Russian territory due to new laws that were passed there. PIA also said that they have updated their apps, rotated all their certificates and improved their encryption algorithms.
As far as this post is concerned, the connection port, encryption cipher and CA’s certificate had to be updated, which I just did.
Just rerun all the steps (not only the shell script) to get things working again. 😉
Great! Thanks so much.
WOW!
Thanks so much! Outstanding job! Keep it up.
Hello, I’m having trouble with this. It asks for my username, which I enter… and then this:
./pia.sh: line 8: wget: command not found
Traceback (most recent call last):
File “”, line 3, in
File “/usr/lib64/python2.7/json/__init__.py”, line 291, in load
**kw)
File “/usr/lib64/python2.7/json/__init__.py”, line 339, in loads
return _default_decoder.decode(s)
File “/usr/lib64/python2.7/json/decoder.py”, line 364, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File “/usr/lib64/python2.7/json/decoder.py”, line 382, in raw_decode
raise ValueError(“No JSON object could be decoded”)
ValueError: No JSON object could be decoded
./pia.sh: line 17: wget: command not found
rm: cannot remove ‘/tmp/openvpn-4856.zip’: No such file or directory
Done
I have followed your instructions, and this is a clean install of fedora24. Can you tell me what I need to do?
oops! I figured it out :p Needed to install ‘wget’, and then restart NetworkManager, as GAtos said. Thank you!
There you go. 😉
Please don’t just run the script. It’s only one piece of the whole setup. You must follow all the instructions.
Hi.
You need to install
wget
, as mentioned in the preparation steps, to download the JSON file which contains the VPN servers’ information. All other error messages are due to the missing JSON file.Hi , and thanks for your replay ,
in fact the script work as a charme on Opensuse.
All i have to do is installing openvpn package with yaST.
And create the pia.sh file and save it to Download folder for example then cd \… to Downloads and run all the commands.
At :
# restorecon -F /etc/openvpn/ca.crt
# restorecon -F /etc/NetworkManager/system-connections/PIA\ *
In the terminal open suse find the right commande to download, install and run it (very simple) all the other commands to are going well in Opensuse 42.1, and after :
# systemctl restart NetworkManager
Everythings goes right !!!
Thank you for this smart and well done job.
Cheers.
Hi this post is simply great , thanks a lot for all, it work both on fedora and Korrora , cant yous please help to install this on Opensuse 42.1, i was thinking that is the same methode but dnf commande does not act on Opensuse terminal.
Thanks for help.
I don’t have experience with openSUSE, but I believe you need to use zypper instead of dnf. The package names might be different too, so you need to adjust them.
Good luck and let me know if it worked.
Well done, thank you so much.
Can’t thank you enough for the post and the script. Completely taken the work out of setting up PIA. I wish I could find blog posts like these for every issue I run into! Thanks again.
Much appreciated.
PIA has an app for Linux available for download here: https://www.privateinternetaccess.com/installer/download_installer_linux
However apparently it only works on Debian based distros like Ubuntu and Mint, it does not work on Fedora.
I tried to analyze it, but it’s coded in Ruby and obfuscated with RubyEncoder. 🙁
A shell script for this:
https://github.com/shaynewang/piafedora
Thanks for pointing that out!
I’ve quickly looked into that shell script. It might be helpful to some people, but it’s basically the same script provided by PIA for Ubuntu with a few modifications. Besides obvious changes like replacing
apt-get
bydnf
and translating Debian’s package names to their counterparts in Fedora, I see that this new script:PASS
is not properly initialized which might cause problems if it was previously defined and the user doesn’t choose to add its password to the VPN files;python
is Python 2.7, which might not be true for older Fedora releases (Python 2.7 is needed to parse the JSON file that contains the VPN servers’ info);/etc/openvpn/ca.crt
. It should beopenvpn_etc_t
(orcert_t
) instead ofhome_cert_t
.Kudos to Shayne Wang for adjusting PIA’s script, and it’s definitely a step in the right direction, but for now I will stick to the steps I described in this post for configuring PIA VPN in Fedora. 🙂
Can confirm this also works on CentOS 7. All you have to do is use yum instead of dnf.
This is great news! Thanks for sharing it. 🙂
Wow!! Thank you so much!! I did have some trouble at one point but I just had to save using unix/linux line endings.
But wow! I had talked to the support yesterday in hopes that they could help me but all they referred me to was something for Ubuntu which isn’t entirely helpful when I’m running Fedora.
It’s actually working!! I’ll be bookmarking this page for sure, maybe even asking the support to refer others to this page if they come into a situation like mine where they are using Fedora. Thanks again!
Thank you very much! Great work!
Awesome, you should put the “dnf” and “systemctl …” parts in the script too, and maybe make a github gist out of this so people can star or fork it 🙂
Hi Robert.
The idea was to describe all the individual steps instead of giving away a script that does everything, so the readers can learn what each step does (if they want).
In the end I had to compromise and put the non-trivial steps in a simple script anyway. It would be too complicated to explain them without making this a monster post. 🙂
Perhaps I should dedicate some time and put all this in a proper shell script…
Thanks for the suggestion!