This post will show my setup using PIA (Private Internet Access) with OpenVPN on a Linux machine. Specifically, where only certain applications will utilize the VPN and the rest of the traffic will go out the normal ISP's default route. It will also show how to access the PIA API via a shell script, to open a forwarding port for inbound traffic. Lastly, I will show how to take all of the OpenVPN and PIA information and feed it to programs like aria2c or curl. The examples below were done on Ubuntu 16.04.
# Install the packages you need, example uses apt-get sudo apt-get install openvpn curl unzip # make dir for PIA files and scripts sudo mkdir -p /etc/openvpn/pia cd /etc/openvpn/pia # grab PIA openvpn files and unzip url='https://www.privateinternetaccess.com/openvpn/openvpn.zip' sudo curl -o openvpn.zip $url && sudo unzip openvpn.zip
Now that we have PIA login info lets make password file so we don't have to put in a password every time we start OpenVPN. We just need to make a file with the PIA username on one line and the PIA password on the second line. So just use you favorite text editor and do this. The file should be called "pass" and put in the "/etc/openvpn/pia" directory. The scripts that are used later depend on this file being called "pass" and put in this specific directory. An example of what the file looks like is below.
piausername piapassword123
Change permission on this file so only root can read it
sudo chmod 600 /etc/openvpn/pia/pass
This is the OpenVPN config file that works with PIA, and that also utilizes the scripts that will be talked about further down in the page. Use your favorite editor and copy and paste this text to a file called "pia.conf" and put in the "/etc/openvpn/pia" directory.
# PIA OpenVPN client config file client dev tun # make sure the correct protocol is used proto udp # use the vpn server of your choice # only use one server at a time # the ip addresses can change, so use dns names not ip's # find more server names in .ovpn files # only certain gateways support port forwarding #remote us-east.privateinternetaccess.com 1198 #remote us-newyorkcity.privateinternetaccess.com 1198 #remote aus.privateinternetaccess.com 1198 #remote us-west.privateinternetaccess.com 1198 remote ca-toronto.privateinternetaccess.com 1198 resolv-retry infinite nobind persist-key persist-tun cipher aes-128-cbc auth sha1 # ca.crt and pem files from openvpn.zip downloaded from pia ca /etc/openvpn/pia/ca.rsa.2048.crt crl-verify /etc/openvpn/pia/crl.rsa.2048.pem tls-client remote-cert-tls server # path to password file so you don't have to input pass on startup # file format is username on one line password on second line # make it only readable by root with: chmod 600 pass auth-user-pass /etc/openvpn/pia/pass # this suppresses the caching of the password and user name auth-nocache comp-lzo verb 1 reneg-sec 0 disable-occ # allows the ability to run user-defined script script-security 2 # Don't add or remove routes automatically, pass env vars to route-up route-noexec # run our script to make routes route-up "/etc/openvpn/pia/openvpn-route.sh up"
If you don't want the vpn to take over your default route then let's keep going. Now that you have left those lines in the pia.conf file, the following script will be run when the client starts, and it will set up a route that does not take over the default gateway, but just adds secondary vpn gateway for programs to use. Open your favorite text editor and copy in the script below into the file "/etc/openvpn/pia/openvpn-route.sh".
#!/bin/sh # script used by OpenVPN to setup a route on Linux. # used in conjunction with OpenVPN config file options # script-security 2, route-noexec, route-up # script also requires route table rt2 # sudo bash -c 'echo "1 rt2" >> /etc/iproute2/rt_tables # openvpn variables passed in via env vars rtname="rt2" ovpnpia="/etc/openvpn/pia" int=$dev iplocal=$ifconfig_local ipremote=$ifconfig_remote gw=$route_vpn_gateway if [ -z $int ] || [ -z $iplocal ] || [ -z $ipremote ] || [ -z $gw ]; then echo "No env vars found. Use this script with an OpenVPN config file " exit 1 fi help() { echo "For setting OpenVPN routes on Linux." echo "Usage: $0 up or down" } down() { # delete vpn route if found ip route flush table $rtname if [ $? -eq 0 ]; then echo "Successfully flushed route table $rtname" else echo "Failed to flush route table $rtname" fi } up() { # using OpenVPN env vars that get set when it starts, see man page echo "Tunnel on interface $int. File /tmp/vpnint" echo $int > /tmp/vpnint echo "Local IP is $iplocal. File /tmp/vpnip" echo $iplocal > /tmp/vpnip echo "Remote IP is $ipremote" echo "Gateway is $gw" down # remove any old routes ip route add default via $gw dev $int table $rtname if [ $? -eq 0 ]; then echo "Successfully added default route $gw" else echo "Failed to add default route for gateway $gw" fi ip rule add from $iplocal/32 table $rtname if [ $? -eq 0 ]; then echo "Successfully added local interface 'from' rule for $iplocal" else echo "Failed to add local interface 'from' rule for $iplocal" fi ip rule add to $gw/32 table $rtname if [ $? -eq 0 ]; then echo "Successfully added local interface 'to' rule for $gw" else echo "Failed to add local interface 'to' rule for $gw" fi # PIA port forwarding, only works with certain gateways # No US locations, closest US is Toronto and Montreal # no network traffic works during exec of this script # things like curl hang if not backgrounded $ovpnpia/pia_port_fw.sh & } case $1 in "up") up;; "down") down;; *) help;; esac # always flush route cache ip route flush cache
Now run some final commands to get the script ready to work
# make the new script executable sudo chmod 755 /etc/openvpn/pia/openvpn-route.sh # make a new route table rt2 in linux for the script to use # this only has to be run once before you connect the first time sudo bash -c 'echo "1 rt2" >> /etc/iproute2/rt_tables'
The following script is run by the openvpn-route.sh script. It will contact a PIA server and tell it to open a port for incoming traffic on your vpn connection. This is so people on the internet can contact your machine through the vpn connection. Just a important note that currently only a certain list of PIA gateways support port forwarding. See the PIA support article on this for more info. Now, open your favorite text editor and copy in the script below into the file "/etc/openvpn/pia/pia_port_fw.sh".
#!/bin/bash # Get forward port info from PIA server client_id=$(head -n 100 /dev/urandom | sha256sum | tr -d " -") url="http://209.222.18.222:2000/?client_id=$client_id" echo "Making port forward request..." sleep 1 curl --interface $(cat /tmp/vpnint) $url 2>/dev/null > /tmp/vpnportfwhttp if [ $? -eq 0 ]; then port_fw=$(grep -o '[0-9]\+' /tmp/vpnportfwhttp) [ -f /tmp/vpnportfw ] && rm /tmp/vpnportfw echo $port_fw > /tmp/vpnportfw echo "Forwarded port is $port_fw" echo "Forwarded port is in file /tmp/vpnportfw" else echo "Curl failed to get forwarded PIA port in some way" fi
# make the new script executable sudo chmod 755 /etc/openvpn/pia/pia_port_fw.sh
Finally we can start OpenVPN to connect with PIA. To do this run the the following command. It will keep the connection in the foreground so you can watch the output.
sudo openvpn --config /etc/openvpn/pia/pia.conf
During startup the OpenVPN client and both of the scripts we made will report on the screen data about the connection and if there were any errors. The output will look like the following example.
Fri Nov 10 19:40:50 2017 OpenVPN 2.3.10 x86_64-pc-linux-gnu [SSL (OpenSSL)] [LZO] [EPOLL] [PKCS11] [MH] [IPv6] built on Jun 22 2017 Fri Nov 10 19:40:50 2017 library versions: OpenSSL 1.0.2g 1 Mar 2016, LZO 2.08 Fri Nov 10 19:40:50 2017 NOTE: the current --script-security setting may allow this configuration to call user-defined scripts Fri Nov 10 19:40:50 2017 UDPv4 link local: [undef] Fri Nov 10 19:40:50 2017 UDPv4 link remote: [AF_INET]172.98.67.111:1198 Fri Nov 10 19:40:50 2017 [dbacd7b38d135021a698ed95e8fec612] Peer Connection Initiated with [AF_INET]172.98.67.111:1198 Fri Nov 10 19:40:53 2017 TUN/TAP device tun0 opened Fri Nov 10 19:40:53 2017 do_ifconfig, tt->ipv6=0, tt->did_ifconfig_ipv6_setup=0 Fri Nov 10 19:40:53 2017 /sbin/ip link set dev tun0 up mtu 1500 Fri Nov 10 19:40:53 2017 /sbin/ip addr add dev tun0 local 10.24.10.10 peer 10.24.10.9 Tunnel on interface tun0. File /tmp/vpnint Local IP is 10.24.10.10. File /tmp/vpnip Remote IP is 10.24.10.9 Gateway is 10.24.10.9 Successfully flushed route table rt2 Successfully added default route 10.24.10.9 Successfully added local interface 'from' rule for 10.24.10.10 Successfully added local interface 'to' rule for 10.24.10.9 Fri Nov 10 19:40:53 2017 Initialization Sequence Completed Making port forward request... Forwarded port is 40074 Forwarded port is in file /tmp/vpnportfw
When the vpn started it dropped some files in /tmp. These files have the ip and port info we need to give to different programs when the startup. The scripts created the following files.
Now you can use this info when you start certain programs. Here are some examples.
# get vpn incomming port pt=$(cat /tmp/vpnportfw) # get vpn ip ip=$(cat /tmp/vpnip) # get vpn interface int=$(cat /tmp/vpnint) # wget a file via vpn wget --bind-address=$ip https://ipchicken.com # curl a file via vpn curl --interface $int https://ipchicken.com # ssh to server via vpn ssh -b $ip# rtorrent /usr/bin/rtorrent -b $ip -p $pt-$pt -d /tmp # start aria2c and background. use aria2 WebUI to connect download files aria2c --interface=$ip --listen-port=$pt --dht-listen-port=$pt > /dev/null 2>&1 &
If you start any programs and don't specifically bind them to the vpn interface or its ip address their connection will go out the default interface for the machine. Please remember this setup only sends specific traffic through the vpn so things like DNS requests still go through the non-vpn default gateway.
Remember only certain PIA gateways support port forwarding so if it is not working, try another PIA gateway. As of this writing, it seems that gateways that support port forwarding are ones not in the USA, like Toronto.
PIA has a Linux vpn client that you can download and use if you are into GUI's.