I recently started using OpenVPN and enjoying the various options it provides, including masking VPN traffic under TCP:443 (otherwise known as HTTPS). Personally, I like using GCE to host my VPNs, because I enjoy the power and customizability it gives.
However, there were absolutely no tutorials on setting up OpenVPN on GCE, so here you go. There are 10 steps in this tutorial, but each step may execute more than one line of code.
If you’re just trying to add more clients, go to steps 4, 9, and 10.
1. Creating the Instance
We want to use an n1-standard-1
instance for its sustainability and cost. Head over to the Compute Engine and hit “CREATE INSTANCE.”
Set it up with the options shown but don’t hit “Create” yet.
In case you can’t see the image, we’re using an n1-standard-1
instance (1 vCPU, 3.75 GB memory) with Ubuntu 16.04 LTS installed (storage space is up to you, but 10 gigs should be good enough). Since our VPN will use TCP:443, we need to allow HTTPS traffic now or later, so might as well do it right off the bat.
Press the “Management, security, disks, networking, sole tenancy” button to open up the advanced options. Click on the Networking tab and hit the edit button next to the selected Network Interface.
Click into the “External IP” dropdown and select “Create IP address.” Enter a name and hit “RESERVE.” This will attach a static IP to your instance, which is probably what you want unless you like regenerating config files every once in a while. As far as charges go, Google doesn’t charge for static IP addresses while they’re being used. The n1-standard-1
machine shouldn’t cost you more than $30 a month. Admittedly, this is a little more expensive than most VPN services, but also most VPN services don’t give you full control :)
Your Network Interfaces should look like the image. Be sure to turn on IP forwarding, as this cannot be changed after the instance has been created.
Generally, you probably want to keep your external IP secret. I don’t mind making this one public since this instance won’t exist when you’ll read this tutorial, and the IP will probably belong to someone else.
Hit “Done” and “Create.” Once the instance is ready (a solid-black “SSH” button will appear), click or double-click on said “SSH” button to open up an SSH window. The rest of the setup will be on this machine, which we will refer to as the “server.”
2. Installing OpenVPN and EasyRSA
OpenVPN is (obviously) the VPN server we’re using, and EasyRSA is a package that will allow us to set up an internal certificate authority (CA) to use.
While I don’t usually do this, for this setup it is often necessary to run an apt update to be able to install one or both of these packages. Both of them are in Ubuntu’s default repositories.
sudo apt-get update
sudo apt-get install openvpn easy-rsa
Time to configure.
3. Setting up the CA
Because OpenVPN uses TLS/SSL, it needs certificates to encrypt traffic. For this, we’ll need to issue our own trusted certificates, which we can do using the CA we’re about to set up.
Let’s start by copying the easy-rsa
package’s template directory.
make-cadir ~/openvpn-ca
cd ~/openvpn-ca
There’s some values that we may want to edit, so let’s go ahead and nano vars
. If you want to use vim, go ahead, but since I’m trying to keep my tutorials as simple as possible I’ll use nano.
From this point on, if there’s a portion of a command that depends on a value you choose, it will be bolded. All code that is not generated by a user will be italicized.
Scroll towards the bottom of the file (it’s not too long) and you should find the following:
export KEY_COUNTRY="US"
export KEY_PROVINCE="CA"
export KEY_CITY="SanFrancisco"
export KEY_ORG="Fort-Funston"
export KEY_EMAIL="me@myhost.mydomain"
export KEY_OU="MyOrganizationalUnit"
Edit as many of these (or none of them) as you like. Just below these values should be export KEY_NAME="EasyRSA"
. To simplify our setup, we’ll change this line to read:
export KEY_NAME="server"
Save and close the file (ctrl+x, y, enter). The variables we just changed will be used for our CA’s signing process. Still inside the openvpn-ca
directory, run the following command:
source vars
If you did that right, the output should read NOTE: If you run ./clean-all, I will be doing a rm -rf on /home/username/openvpn-ca/keys
. This is what we want. To ensure a clean working environment, we’ll run ./clean-all
.
Now, let’s build the CA.
./build-ca
All of the variables we already set should populate themselves, so just skip through by pressing enter a few times. At the end, you will have a CA ready to start signing.
We also need a server certificate and an encryption key to ensure our traffic is secure.
Let’s create our server certificate and key.
./build-key-server server
Skip through the prompts once again. We won’t enter a challenge password this time. The last two prompts require you to enter y
to sign the certificate. Make sure to not skip past those!
As noted before, we also need an encryption key. For the purposes of this tutorial, we’ll generate a Diffie-Hellman key, which tends to be rather strong. Of course, with great [strength] comes great [inefficiency], so regardless of your system the following command will probably take a few minutes.
./build-dh
We’ll strengthen this with an HMAC signature, to ensure our TLS integrity verification is safer.
openvpn --genkey --secret keys/tiv.key
4. Generate a Client Certificate
Naturally, if you’re going to use a CA, your client needs to have a certificate too. While you can do this on your client machine and then have the server sign it, we’ll try to keep things simple and hosted on one machine.
If you have more than one client, you can follow this step multiple times. Just make sure to make your client names unique.
Make sure that you’re in the openvpn-ca
directory and that your vars
file is in sync.
cd ~/openvpn-ca
source vars
Now, we’ll build a client key as such:
./build-key client
Everything should once more be pre-populated, so skip through all except the last two prompts, which will ask you to sign by entering y
.
5. Set up the OpenVPN Server
OpenVPN installs itself under the /etc/openvpn
directory. To make sure everything works, we need to move some files into that folder.
cd ~/openvpn-ca/keys
sudo cp ca.crt server.crt server.key tiv.key dh2048.pem /etc/openvpn
By default, OpenVPN comes with a sample configuration. For the sake of simplicity, we’ll simplify unzip this into our config folder.
gunzip -c /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz | sudo tee /etc/openvpn/server.conf
Next, we’ll go ahead and edit the config file:
sudo nano /etc/openvpn/server.conf
The first step is to find the tls-auth
directive. There will be a semicolon (;) next to the directive, which we’ll remove. Underneath, we’ll add a line.
tls-auth tiv.key 0 # This file is secret
key-direction 0
We also need to cipher our server, so let’s edit the cipher directives right below this section. Specifically, we’ll uncomment the AES-128-CBC line and add an auth
directive.
cipher AES-128-CBC
auth SHA256
Next up are the user and group settings:
user nobody
group nogroup
Optionally, we might opt to send all traffic through the VPN. For this, find the redirect-gateway
directive and uncomment it.
push "redirect-gateway def1 bypass-dhcp"
Right below, there should be a couple of dhcp-option
lines. Uncomment those too.
push "dhcp-option DNS 208.67.222.222"
push "dhcp-option DNS 208.67.220.220"
Optionally, we might want to change the port and protocol that OpenVPN operates on. The default is UDP:1194, but if your network blocks VPN connections, that will probably be one of the victims. The disguise would be to use TCP:443, which is the HTTPS port.
port 443proto tcp
;proto udp
If you didn’t use “server” as your server name, your crt
files have a different name. Update them accordingly.
cert server.crt
key server.key
Save and close the file.
6. Preparing Ubuntu
While we already set up IP forwarding and whatnot, there’s a couple other changes we need to make to enable these options.
sudo nano /etc/sysctl.conf
Look for the following line and remove the # (comment character).
net.ipv4.ip_forward=1
Save and close. To update session settings, run:
sudo sysctl -p
Next, we need to find and update our firewall (UFW) rules to masquerade clients. The first step is to find the interface that we’re running on:
ip route | grep default
The interface we want is the one that has the word “dev” in it. In our case, that looks like this:
default via 10.138.0.1 dev ens4
So, our interface is ens4
. With this, we’ll update our firewall rules:
sudo nano /etc/ufw/before.rules
Above where it says Don't delete these required lines...
add the following code:
# OPENVPN
# NAT Table
*nat
:POSTROUTING ACCEPT [0:0]
# OpenVPN client traffic
-A POSTROUTING -s 10.8.0.0/8 -o ens4 -j MASQUERADE
COMMIT
# OPENVPN
Save and close. Next, we need to forward packets.
sudo nano /etc/default/ufw
Find the DEFAULT_FORWARD_POLICY
directive and change it from "DROP"
to "ACCEPT"
.
DEFAULT_FORWARD_POLICY="ACCEPT"
Save and close.
7. Running OpenVPN
To start the server, run the following:
sudo systemctl start openvpn@server
To check that it started properly, run:
sudo systemctl status openvpn@server
If everything went well, you should see some output that includes Active: active (running)
. You might need to hit q
to exit the information panel. If you’re good, link the service to the startup sequence.
sudo systemctl enable openvpn@server
8. Setting up a Client Configuration Structure
For ease of setting up client configs, we’ll first create a structure. To start, create a config folder to store the client config files.
mkdir -p ~/clients/files
The client keys will be within these configs, so let’s lock the permissions on the files
directory.
chmod 700 ~/clients/files
Copy the sample configuration.
cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf ~/clients/base.conf
Let’s edit the file:
nano ~/clients/base.conf
Find the remote
directive. Replace the my-server-1
with the public external IP address that was assigned to your GCE instance. If you chose a port other than 1194, update that accordingly.
remote 35.197.111.236 443
Also update your protocol.
proto tcp
Uncomment user and group:
user nobody
group nogroup
Find the ca
, cert
, and key
directives and comment them out, since our configs will include these automatically.
# ca ca.crt
# cert client.crt
# key client.key
Use the same cipher and auth settings as before:
cipher AES-128-CBC
auth SHA256
Somewhere, we’ll need to add key-direction
. Make sure to use 1, as this is for the client now. 0 was for the server.
key-direction 1
If your current client config is (or will be) used on a Linux device, add the following:
script-security 2
up /etc/openvpn/update-resolv-conf
down /etc/openvpn/update-resolv-conf
Note that if you include these in a non-Linux environment (Android and macOS included in non-Linux), your clients may act strangely.
Save and close. Next, we need to write a script to generate our client configs quickly and easily.
nano ~/clients/gen_config.sh
Inside, paste this code:
#!/bin/bashKEY_DIR=~/openvpn-ca/keys
OUTPUT_DIR=~/clients/files
BASE_CONFIG=~/clients/base.confcat ${BASE_CONFIG} \
<(echo -e '<ca>') \
${KEY_DIR}/ca.crt \
<(echo -e '</ca>\n<cert>') \
${KEY_DIR}/${1}.crt \
<(echo -e '</cert>\n<key>') \
${KEY_DIR}/${1}.key \
<(echo -e '</key>\n<tls-auth>') \
${KEY_DIR}/tiv.key \
<(echo -e '</tls-auth>') \
> ${OUTPUT_DIR}/${1}.ovpn
The {1}
here refers to the first argument, which will be our client name. Make sure to update tiv.key
according to your HMAC key name.
Allow execution of this script:
chmod 700 ~/clients/gen_config.sh
9. Generate Client Configs
The step you’ve all been waiting for is finally here. We’ll generate our client configs.
cd ~/clients
./gen_config.sh client
Check that this worked by running:
ls ~/clients/files
If it did, there should be a client.ovpn
file in this directory now. We need to download this file and transfer it to our devices. To do this, click on the gear icon in the top right of the SSH session, and select “Download file.”
The fully qualified path should be something like this:
/home/username/clients/files/client.ovpn
10. Installing on Clients
For Windows, download the client app from the OpenVPN downloads. Once installed, move your client.ovpn
file to C:\Program Files\OpenVPN\config
. To open OpenVPN, you must run the app as administrator. Once inside, you should see and be able to connect to your VPN.
For macOS, most people suggest using Tunnelblick although any other OpenVPN client (while safe) is probably good too. Once installed, you should be able to drag any .ovpn
file to the Tunnelblick icon on the menu bar to install the configuration. Use the menu bar to then connect to the VPN. If you’re asked about the down-root.so
plugin, make a decision! I skipped it because I’m fine with reconnecting my connection, but it’s up to you.
On Linux, install the openvpn
package using your package manager. CentOS users will need to install epel-release
using yum
first. Once installed, run ls /etc/openvpn
. If the output does not show an update-resolve-conf
file, you need to edit your .ovpn
file and remove the following lines (if you had added them):
script-security 2
up /etc/openvpn/update-resolv-conf
down /etc/openvpn/update-resolv-conf
If you never added those lines but found an update-resolv-conf
file, add them! CentOS users will need to change the group
in the .ovpn
file from nogroup
to nobody
to comply with the operating system’s standards.
To connect, run sudo openvpn — config client.ovpn
.
For iOS, install the OpenVPN Connect app. Next, open up iTunes on your computer and navigate to iPhone > Apps. Scroll to the “File Sharing” section and select “OpenVPN.” Drag your .ovpn
file into the “OpenVPN Documents” panel. Opening the app on your phone should now show you a message saying a new profile is ready for import. Once imported, you should be able to connect to the VPN.
For Android, install the OpenVPN Connect app. Next, transfer your .ovpn
file anywhere/anyhow on to your device (I just used Google Drive, but that might not be recommended). In the app, open the menu and click “Import.” Navigate to your .ovpn
file, click on it, and hit “IMPORT” at the top right. Once completed, you should be able to connect to the VPN.
Testing the VPN
The easiest way to test your VPN would be to Google “what’s my IP address” before and after connecting to it. Your IP should change to your GCE instance’s external public IP once you’re connected to the VPN, and back to your network IP once disconnected form the VPN.
If all went well, that’s it! Your new VPN is ready for use.
Cheers!
Credits
This article is based largely off of this tutorial on the DigitalOcean community. While the setup itself is fairly similar, I thought to write a separate article because there are a few key things that are different in GCE and quite easy to get wrong if you’re doing this for the first time (I speak from experience).
If you need a second opinion, you can always turn to that article. The last section on that page also shows a way to revoke client certificates, in case you offer your VPN service to someone who goes MIA :)
Questions, comments, and concerns are always welcome. Feel free to drop me a line in the comments!
This was my first story (and the first story) on TeenDevs, so any form of support would be very greatly appreciated!