Internet users are spoiled for choice when it comes to VPN services, but they either require a monthly subscription, aren’t secure, or are just plain slow. Thankfully, alternatives do exist. They require a bit more technical know-how, but if you want something done right, you have to do it yourself.
To learn how to make your own VPN, you can watch the video or read the article. Note that the article contains some useful commands and configuration text that you can copy and paste for your convenience. Update: the video uses an old version of easy-rsa that is no longer available. When you get to the 8-minute mark, please refer to this article for easy-rsa 3 configuration.
Amazon Web Services offers one year of free virtual server space, provided you use less than predetermined amounts of bandwidth, time, and space. Even if you go over that limit, the cost of running a server image on Amazon’s Elastic Compute Cloud is probably less than you would pay for a VPN subscription.
Here we’ll explain two different ways to use Amazon’s Elastic Cloud service, also called EC2, to divert your connection through a private location of your choice: SSH Tunneling and OpenVPN. Each has advantages and disadvantages, so use the one you find more suited to your needs. No matter which you choose, you’ll require the following:
- An Amazon Web Services account. This requires a credit card, but you’ll only be charged for what you use, which will likely be nothing if you’re prudent about what you’re doing.
- PuTTy, if you’re on Windows. OpenSSH via Cygwin is another option, but I found it to be a pain. Linux and Mac computers already have SSH prompts built into their boxes and terminals. You’ll also need PuTTy’s sister key generation program, PuttyGen.
- WinSCP, or an equivalent FTP client to move files between your local computer and your EC2 instance.
- A basic working knowledge of Unix commands and how servers work with clients will be massively helpful in troubleshooting should something not go exactly as planned.
- OpenVPN GUI, installed in the default location and with the default settings on your PC
On the top right, you can choose the location where we’ll be setting up your VPN. Click Launch Instance.
Choose whatever Linux AMI is listed as “free tier eligible.” At the time of writing this article, that’s the Amazon Linux AMI. Go on to the next step.
Here choose a t2.micro instance that’s also free tier eligible. Click “Review and Launch.”
On the next page,
you should get a warning message asking you to edit your security groups. Click Edit Security Groups.
You’ll need edit the security group to only allow traffic from your computer to access the VPN or proxy. You should have one rule already in place for connecting to your server via SSH, which we’ll use later. We’ll need to add another to allow OpenVPN connections, which use port 1194 by default. For simplicity’s sake, under the Inbound tab, click the Add rule button. Set the Type to Custom UDP, the Port Range to 1194, and the Source to Anywhere.
Click “review and launch,” then “launch” on the next page.
Now you’ll want to create a key pair, which sort of works like a password that you’ll use to connect to the virtual server you’re creating. Select “create a new key pair” from the dropdown menu and name it whatever you like. Click the button to download the key pair. Store it somewhere safe.
The next page should alert you that the instance is launching. Scroll to the bottom and hit “View instances.” Here you’ll see a list of any instances you’ve launched, which if this is your first time using EC2 will just be one.
We can connect to our EC2 instance with PuTTy, but first we’ll need a proper key file to get connected. When you installed PuTTy, you should have also installed PuTTygen. Go ahead and run it now.
PuTTy and PuTTygen both run right out of the box as .exe files with no need to install. Open PuTTygen, click Load. Navigate to the .pem key pair file you downloaded before and load it into Puttygen. You’ll have to select the option to show all file types for the .pem key to show up. Hit “Save Private Key.” The file name must be identical to the .pem key. You can create a passphrase for the private key if you want.
Now close out of PuTTygen and open PuTTy. Copy your instance’s public IP from the EC2 console into PuTTy. Type in a name for your session and hit save.
In the left pane, navigate to “Auth” under SSH. Click the browse button at the bottom and navigate to the private key you just generated.
Back on the main Session page, name and save your session profile so you can quickly connect the next time you use PuTTy. Then Click Open. A prompt will appear asking you for a username. This differs based on what type of server you set up at the beginning. For the Amazon Linux AMI, it’s “ec2-user”.
SSH Tunneling (optional)
To begin with, we’re just going to reroute web traffic through the instance we created using SSH tunneling and a proxy. This is a quick and dirty way to get around a firewall or geographic lockout. It’s not quite a VPN–it’s best for light web traffic and won’t work with everything–but it’s much more simple to set up. However, setting up SSH tunneling is entirely optional, so feel free to skip to the next section.
Open PuTTy and navigate to Tunnels in the left pain. Add port 8080 with Auto and Dynamic selected. Go back to the Session page and hit Save again so you don’t have to do all this over again. Then click Open.
Now you’re connected to your server, but you still need to route your web browser’s traffic through it. If you use Firefox, this can be done in your browser settings. If you use Chrome, download the Proxy Switchy extension. If you prefer to create a fully functioning VPN rather than just a proxy for your browser, skip to the next section now.
- Go to Tools > Options > Advanced > Network > Connection > Settings > Manual proxy configuration
- Set SOCKS Host as 127.0.0.1 and the port as 8080 (or whatever you set the tunnel port to on PuTTy).
- Click OK to save
In Chrome Proxy Switchy
- A setup page should appear as soon as you install the extension, or click the icon in the top right of Chrome and click Options.
- Name the profile whatever you like. Under Manual Configuration, set the SOCKS host to 127.0.0.1 and the port to 8080 (or whatever you set the tunnel port to in PuTTy. Leave everything else blank.
- Hit Save, then click the icon again to select your proxy profile.
Voila! Your browser traffic is now being funneled through your EC2 instance. This will work fine for basic browsing, but some websites might run into problems and apps other than your web browser will still use the direct connection. To create a full-on VPN that reroutes all your internet traffic, read on.
Set up OpenVPN on the server and client
OpenVPN is a free open source tool that will let you run a full-on VPN through your Amazon EC2 instance. That means all your internet traffic goes through it, not just your web browser traffic like the proxy above. Desktop programs such as Steam or Spotify work better with this approach.
Connect to your EC2 instance using PuTTy according to the instructions above. You should have a command prompt in front of you that says Amazon Linux AMI. Run the following commands (type or copy/paste them and press enter):
sudo yum install -y openvpn sudo modprobe iptable_nat echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward sudo iptables -t nat -A POSTROUTING -s 10.4.0.1/2 -o eth0 -j MASQUERADE sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
Just a quick note here. You might have noticed in the screenshot that I incorrectly tried to download and install OpenVPN using the “apt-get” command instead of “yum”. Some other versions of Linux still use apt-get, so if yum doesn’t work for you, try this command instead:
sudo apt-get install -y openvpn
A bunch of text will flash on the command prompt while it installs OpenVPN. The other three commands set up IP forwarding, which is necessary for the VPN to work.
Method #1: Setting up PKI authentication with easy-rsa (recommended)
In the original version of this tutorial, we set up OpenVPN with static encryption and a .ovpn file. While that works, it only allows one device to be connected at a time, and the fact that you only ever use one key means it’s less secure. We now recommend readers use easy-rsa to set up authentication, which is more secure and allows for any number of devices to be simultaneously connected. However, if you want the old version with static encryption, skip to it by clicking here.
May 2018 update: This article has been updated for use with easy-rsa 3.
Easy-rsa is not available in the default yum package list, so we’ll need to enable the EPEL repo to install it. Type the following into the PuTTy terminal and hit Enter:
sudo yum install easy-rsa -y --enablerepo=epel
Ideally, you would generate all the keys and certificates you need on a separate device from the VPN server for maximum security. This can be quite tedious, however, so we’re just going to generate both client and server credentials on the server, then move the files where we need them from there.
Make an easy-rsa directory in your OpenVPN install directory. Copy the files from your easy-rsa installation (latest version is 3.0.3 as of time of writing) to the new directory:
sudo mkdir /etc/openvpn/easy-rsa cd /etc/openvpn/easy-rsa sudo cp -Rv /usr/share/easy-rsa/3.0.3/*
Now we’re ready to set up our certificate authority. Start by initializing a new PKI (public key infrastructure) directory, then build a certificate authority keypair.
sudo ./easyrsa init-pki sudo ./easyrsa build-ca
Enter a PEM passphrase. This is not required but recommended. If someone gets a hold of your CA somehow, they will not be able to create keys or sign certificates without the password.
You’ll be prompted to enter a common name. Call it whatever you want or just hit Enter to leave it as the default value.
Next, we’ll generate a Diffie-Hellman key, which provides perfect forward secrecy:
sudo ./easyrsa gen-dh
This command can take awhile. It will generate a file called dh.pem. Once finished, we move on to the server credentials. For convenience, we won’t password protect these, but you’re certainly welcome to do so if you want even harder security.
sudo ./easyrsa gen-req server nopass
Hit Enter to leave the common name as server. Once the key pair is generated, sign the certificate:
sudo ./easyrsa sign-req server server
Type yes to confirm and enter your CA password if you set one earlier.
Now we’ll set up the client. Again, we won’t set a password on this but you are welcome to. Note that if you want to configure automated VPN startup, it’s best not to set a password.
./easyrsa gen-req client nopass
Hit Enter to leave the common name as client. Now sign it:
sudo ./easyrsa sign-req client client
Type yes to confirm and enter your CA password if you set one.
Next, we’ll generate a TLS key for perfect forward secrecy in OpenVPN, which ensures past session data cannot be decrypted even if an attacker gets hold of our private key.
cd /etc/openvpn openvpn --genkey --secret pfs.key
We’ve now generated all of the credential files we need. Next, we’ll create an OpenVPN server configuration file. We’ve already got one written up for you below, so all you need to do is copy and paste if you’ve followed along from the beginning. Start by navigating to the OpenVPN directory and creating a new file:
cd /etc/openvpn sudo nano server.conf
You are now in the nano text editor. Copy and paste the following config, then hit CTRL+O to save, Enter to confirm, and CTRL+X to exit. (Hint: you can paste text from your clipboard into PuTTy just by right-clicking)
port 1194 proto udp dev tun ca /etc/openvpn/easy-rsa/pki/ca.crt cert /etc/openvpn/easy-rsa/pki/issued/server.crt key /etc/openvpn/easy-rsa/pki/private/server.key dh /etc/openvpn/easy-rsa/pki/dh.pem cipher AES-256-CBC auth SHA512 server 10.8.0.0 255.255.255.0 push "redirect-gateway def1 bypass-dhcp" push "dhcp-option DNS 126.96.36.199" push "dhcp-option DNS 188.8.131.52" ifconfig-pool-persist ipp.txt keepalive 10 120 comp-lzo persist-key persist-tun status openvpn-status.log log-append openvpn.log verb 3 tls-server tls-auth /etc/openvpn/pfs.key
The server is now configured. We just need to start up OpenVPN. We’ll start it as a service so that even after you close PuTTy, it will continue to run until the server is either shut down or you manually end the service.
sudo service openvpn start
Edit: Some readers have pointed out that their VPN servers stop working after a server reboot or maintenance. This happens occasionally with micro tier EC2 instances. To prevent this, we’ll use a command and bash script courtesy of Matt Doyle in the comments section. Start with this command:
sudo chkconfig openvpn on
While you’re still in etc/openvpn, use nano server.sh to create a new text file and paste the following into it:
#!/bin/sh echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward sudo iptables -t nat -A POSTROUTING -s 10.4.0.1/2 -o eth0 -j MASQUERADE sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
Use CTRL+O to save and CTRL+X to exit.
The command will ensure OpenVPN starts when the server boots, and the script will ensure the necessary routes are set up in iptables to allow OpenVPN traffic.
Now that the server is configured, we need to set up the client. To do that, we’ll have to move the necessary certificate and key files from our server to our client device. With PuTTy still open and running as root, we first need to change the permissions on these files so that we can access them. We’ll also put them all in one place to make things a bit easier. To access some of these files, we’ll need to be root user. To do that, type:
This will make you the root user and grant administrative privileges. Now enter the following commands:
cd /etc/openvpn mkdir keys cp pfs.key keys cp /etc/openvpn/easy-rsa/pki/dh.pem keys cp /etc/openvpn/easy-rsa/pki/ca.crt keys cp /etc/openvpn/easy-rsa/pki/private/ca.key keys cp /etc/openvpn/easy-rsa/pki/private/client.key keys cp /etc/openvpn/easy-rsa/pki/issued/client.crt keys chmod 777 *
The last command lowers the required permissions to access these files. It’s important to change them back when finished.
To get the files off of our server and onto our PC, we’ll use a free program called WinSCP. Just use the default installation options. Once that’s done, a window should pop up prompting you to import your server authentication details from PuTTy. Select the one we made above and continue.
Select myvpn (or whatever you named yours) and hit the Edit button. Type in ec2-user under user name. Click on Login.
If this isn’t your first time using WinSCP, you can set the .ppk file you used in PuTTy by clicking Edit and Advanced. Go to SSH > Authentication > Private key file and navigate to your PPK file. In the host name field on the main page, you can enter either the IP address or domain of your EC2 instance. Be sure to save your settings, then hit Login.
In the right pane, navigate to the directory containing your key files, in this case /etc/openvpn/keys
Highlight the six files you’ll need: client.crt, client.key, ca.crt, dh.pem, pfs.key, and ca.key (not shown due to article update). Hit the green Download button. It doesn’t really matter where they go on the left pane so long as you don’t need admin privileges to access it. We put the files on our desktop for simplicity’s sake. However, you’ll want to store the ca.key file somewhere safe, such as a USB drive.
The last loose end we need to do tie up is removing the ca.key file from the server. The CA, or certificate authority, is used to sign client certificates,and, if it is ever compromised, you can never trust certificates issued by that CA again. While this isn’t necessary for the VPN to work, we strongly recommend doing it, especially if you didn’t set up a password for the CA. Make sure you’ve all the keys and certificates for every device you want to connect before removing the file. If you want to add more at a later time, you will have to move the ca.key file back onto the server.
Once you have the CA key safely stored somewhere other than the server, go into PuTTy and remove both the the original ca.key and the copy we made from the server:
sudo rm /etc/openvpn/easy-rsa/pki/private/ca.key sudo rm /etc/openvpn/keys/ca.key
Once the files have downloaded, we need to restore their stricter permissions on the server so not just anyone can access them. Back in PuTTy:
cd /etc/openvpn/keys sudo chmod 600 *
On your PC, cut and paste those five files from wherever you downloaded them into your OpenVPN config folder. In this case that’s C://Program Files//OpenVPN//config.
Lastly, we need to create a client configuration file. Open your favorite plaintext editor (Notepad works fine) by right clicking and selecting Run as administrator and paste the following config, replacing YOUR.EC2.INSTANCE.IP with the IP address of your EC2 instance:
client dev tun proto udp remote YOUR.EC2.INSTANCE.IP 1194 ca ca.crt cert client.crt key client.key tls-version-min 1.2 tls-cipher TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256 cipher AES-256-CBC auth SHA512 resolv-retry infinite auth-retry none nobind persist-key persist-tun ns-cert-type server comp-lzo verb 3 tls-client tls-auth pfs.key
This is a Windows config file for the OpenVPN GUI, so we’ll save it as client.ovpn. Other OpenVPN clients might use the .conf extension instead. Whatever the case, make sure your text editor doesn’t add the .txt extension after saving. Save it into the same location as your key and certification files: C:\\Program Files\\OpenVPN\\config
Now run the OpenVPN GUI in administrator mode by right clicking it and selecting Run as administrator. Right click the icon in your system tray and connect with the client configuration we just set up. A status screen with loads of text will flash across the screen, and then the icon will turn green.
Congratulations! You are now connected to your homemade VPN.
Method #2: Static encryption (easier, but not recommended)
In this method, we’ll create a shared key for authentication. It’s sort of like a file that acts as a password. It’s easier to set up but only allows a single device to be connected to the VPN at any one time, and is less secure than the easy-rsa method above. In PuTTy Type in the following commands and hit enter:
cd /etc/openvpn sudo openvpn --genkey --secret ovpn.key
Now we’re going to create a server config file for our VPN. Type the following command to create a blank text file in a very basic text editor inside the terminal:
sudo nano openvpn.conf
Type in the following configuration. You can find more options on the OpenVPN website if you want to play around with this later, but make sure you know what you’re doing first.
port 1194 proto tcp-server dev tun1 ifconfig 10.4.0.1 10.4.0.2 status server-tcp.log verb 3 secret ovpn.key
sudo service openvpn start
Next we need to get the shared key from the server to your local computer. First we need to change the permissions on that file so we can access it using the following command:
sudo chmod 777 ovpn.key
If at any point you accidentally close PuTTy or it just craps out, you can navigate back to your open VPN installation directory after reconnecting using this command:
To make this as easy as possible, download and install this free application, WinSCP (Mac users will have to find another FTP client. Don’t worry, there are lots of them). Just use the default installation options. Once that’s done, a Window should pop up prompting you to import your server authentication details from PuTTy. Select the one we made above and continue.
Select myvpn (or whatever you named yours) and hit the Edit button. Type in “ec2-user” under user name. Click on Login.
Now you can move files between your EC2 instance server and your local computer. On the right hand panel, navigate up as far as you can, then go to etc/openvpn. Here you’ll find the ovpn.key file that we need. Click and drag it into the folder of your choice, but remember where you put it as we’ll want to move it later.
Now that you have the key, we need to re-apply the old permissions so not just anyone can grab it. Back in your PuTTy terminal, enter:
sudo chmod 600 ovpn.key
It’s time to download the OpenVPN client and GUI for your local computer. Go to the OpenVPN downloads page and choose the appropriate version for your operating system. Install it with the default settings. It should appear in your system tray as an icon once launched. Open up a file explorer and navigate to where you installed OpenVPN, probably in your Program Files folder. Move the opvn.key file we downloaded from the server to the config folder found here (C:/Program Files/OpenVPN/config … if you used the default installation directory on Windows).
Next we need to create a config file for the local machine to match the one we made on our server. Open up Notepad and paste the following, replacing the IP address after “remote” with the IP of your EC2 instance (if you’ve forgotten it, find it in your AWS Console under EC2 Instances). Also double check that the full file path pointing to your key is correct.
proto tcp-client remote <your EC2 IP here> port 1194 dev tun secret "C:\\Program Files\\OpenVPN\\config\\ovpn.key" redirect-gateway def1 ifconfig 10.4.0.2 10.4.0.1
Save it as myconfig.ovpn (make sure your text editor doesn’t append it as myconfig.ovpn.txt by mistake) in the config folder of your OpenVPN installation, the same place as your opvn.key file.
Right click on the OpenVPN icon in your system tray and click Exit to quit. Now start it up again–either from the desktop shortcut or from the Program Files folder–but this time use right click and hit “Run as administrator”. If you don’t run OpenVPN as administrator on Windows, it probably won’t work.
Right click the system tray icon and click Connect. The OpenVPN GUI should pop up showing you the connection status. Assuming it worked, the system tray icon will turn green. Go to Google and type in “What’s my IP?”, and it should return the IP address of your Amazon EC2 Instance.
Congratulations, you just made your own VPN!
If you want to protect your VPN from deep packet inspection, a technique used by censorship regimes in places like China and Syria to block OpenVPN connections, check out our tutorial on setting up Obfsproxy. Note this tutorial was written as a sort of sequel to the older Method #2 in this article, so if you used easy-rsa, it will require some additional configuration.
Remember to keep your bandwidth within Amazon’s free tier limits. The easiest way to do this is to right click on your instance in the AWS Console and click on the “Add/Edit Alarms” link. You can set your server to stop or even terminate after a few hours of inactivity. The free tier allows for 750 hours per month (which covers the whole month), so you shouldn’t need to do this. Those users past their initial free year of service or doing more with their server, however, can prevent unnecessary charges for unused server time.
Somewhere in this tutorial, something will probably go wrong for you. If you really want a VPN but aren’t willing to do your fair share of troubleshooting, it’s probably best to opt for a paid VPN service. They also allow you to channel your internet traffic through multiple geographic locations, where as an EC2 instance is limited to just one. Check out our VPN reviews here!
Hardcoding DNS servers into your VPN
If you need to set specific DNS servers to use with your VPN, there are a couple of options.
To “push” the DNS server to the client, add this line to the server config. This will affect all of the devices that connect to your VPN (quotes included):
push "dhcp-option DNS 184.108.40.206"
Alternatively, you can set the DNS in an individual client config using:
dhcp-option DNS 220.127.116.11
In these examples I used an OpenNIC public DNS server with anonymous logging located in the US. You can find a OpenNIC server in the country of your choice and filter by features like anonymous logging and DNSCrypt here.
Special thanks to Dctr Watson’s blog, which I leaned on as a resource when writing this article.
Jon Watson (no relation, I think) contributed to this article.