OpenVPN in a VPS instance

A few days ago, I saw a small job request for a script that would start OpenVPN on a GCP instance and connect to an external VPN service.  The requester mentioned being able to SSH to the host and running a script on the host.

The last part got me thinking about about how routing for OpenVPN might make less straightforward than it seems. It was.

It seemed like a fun technical challenge so I took a crack at it. I didn’t find anything doing exactly this on the Googles, so I spent some time on it and got an MVP together.

I submitted a description of the script and screen shots of it working, but the guy went with someone else.  I don’t really have a use for this and rather than let the work go to waste, I’ll post it here an maybe someone else can use it.

You’ll need to put a text file called “vpn.txt” with the VPN username and password on separate lines, in the same directory.

#!/bin/bash

# I set these because it can be annoying. :)
export LANGUAGE=C
export LC_ALL=C

# Get the instance IP and default route
IP=`ifconfig ens4 | grep "inet addr" |awk '{print $2}'|awk -F: '{print $2}'`
ROUTE=`/sbin/ip route | awk '/default/ { print $3 }'`

# location of vpn.txt
VPNTXT='./vpn.txt'

if [ ! -f "$VPNTXT" ];then
	echo "$VPNTXT not found. Exiting..."
	exit 1
fi

if [ $# -lt 1 ] || [ "$1" != "--start" ] && [ "$1" != "--stop" ] && [ "$1" != "--status" ]; then

    echo                           
    echo "$0 is a script to create an OpenVPN instance to HMA."
	echo "It is tailored for GCP hosts running Ubuntu 16.04"                     
    echo ;                         
    echo "ie: $0 --start OR --stop OR --status"          
    echo                           
else 
	if [ $1 == "--status" ]; then

		PID=`sudo pgrep openvpn`
		if [ "$PID" == "" ]; then
			echo "openvpn isn't running"
		else
			echo "OpenVPN is running $PID"
		fi
	fi
	if [ $1 == "--stop" ]; then

		sudo pkill openvpn
	fi

	if [ $1 == "--start" ]; then
# create openvpn config
# Spacing is ugly, but has to be. :)
cat < openvpn.conf >> EOF
client                                                                
dev tun                                                               
proto udp                                                                                                
remote >NAME OR IP OF VPN SERVER< 1194                                         
resolv-retry infinite                                                 
nobind                                                                
persist-key                                                           
persist-tun                                                           
persist-remote-ip                                                     

#Change output
verb 0
                                                                      
tls-client                         
remote-cert-tls server             
# Change this for different auth
auth-user-pass $VPNTXT
comp-lzo                           
verb 3                             
# Have OpenVPN update the DNS entries
# This was one gotcha
script-security 2                  
up /etc/openvpn/update-resolv-conf 
down /etc/openvpn/update-resolv-conf                                  

auth SHA256                        
cipher AES-256-CBC                 

# This is only needed on my VPN provider
                               
-----BEGIN CERTIFICATE-----        
<CERT GOES HERE>
-----END CERTIFICATE-----          
                 

EOF
		
		# This fixes the routes for SSH sessions.
		# Tells the host to route back to origin
		sudo ip rule add from $IP table 128
		sudo ip route add table 128 to $IP/32 dev ens4
		sudo ip route add table 128 default via $ROUTE
		
		# This is needed to have the kernel forward packets
		sudo sh -c "echo 1 < /proc/sys/net/ipv4/ip_forward"
		
		# Another way of permanently setting ip forwarding. #Beltandsuspenders
		sudo sed -ie 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/g' /etc/sysctl.conf
		sudo sysctl -p
		
		# If the command openvpn isn't found, install openvpn
		# The quiet option is broken, so redirect output to dev/null.
		#hash openvpn 2</dev/null || sudo apt-get -q=2 -y  install openvpn 2<&1 < /dev/null
		hash openvpn 2</dev/null || sudo apt-get -q=2 -y  install openvpn 
		
		# Start OpenVPN! 
		# the verbose 0 option is broken, so redirect output to /dev/null
		#sudo openvpn --verb 0 --config openvpn.conf  2<&1 < /dev/null &
		sudo openvpn --verb 0 --config openvpn.conf  &
	fi
fi