Run a Free VPN Server on AWS (2022 Edition)
This tutorial will take you through the steps of setting up an EC2 instance running OpenVPN server. It will then cover how to grant and revoke access to your VPN server.
AWS has an awesome firewall built into its core services, which can easily be used to make sure that only certain ports are open to the outside world. One extra step that we can take is to run a VPN server that serves as the gateway to our protected AWS resource, e.g. EC2, RDS, etc… We can then shutdown direct access to our AWS resources just by revoking access via our VPN server. This is very useful if you need to revoke access for a former employee.
AWS now offers a managed VPN Service, but this service costs at least $72 a month and is even more expensive when your VPN serves a lot of traffic. A lot of smaller organizations don’t need all the features of the managed service and instead can run their own VPN server for just the cost of an EC2 instance. You can even use the free tier so that you don’t have to pay anything for the EC2 instance for the 1st year.
Step 1 — Create the VPN Security Group
Overview: security groups allow your servers to communicate with each other in a private cloud while exposing specific ports to the world. We are going to create a security group to allow VPN access to our VPN server. We will assume that all your other AWS resources are members of the default security group and that the default security group does not allow access from the outside world.
Log in at https://aws.amazon.com, type EC2 in the search box, and click on the target to go to the EC2 Dashboard.
From the EC2 dashboard, click Security Groups:
Click Create security group:
Enter a name and description of vpn and specify the following inbound rules on ports 22, 443, 943, and 1194. Note: the protocol for port 1194 is UDP.
Note: if the IP addresses that your team uses are static then you can add yet another layer of security by specifying an IP address range in the Source of your rules. However, you’ll want to leave the Source open to anywhere if you want your team to be able to connect from any IP as they may be working from a hotel, home, cafe, etc…
Step 2 — Create the EC2 Instance
Return to the EC2 Dashboard and then click Launch instances:
Select Ubuntu (you can of course select almost any other OS that runs OpenVPN, but this tutorial is tailored to Ubuntu)
Select t2.micro:
Note: you can use a nano instance instead of a micro instance, but nano instances are not eligible for the free tier.
In the Network settings section, select your default VPC and disable the auto-assign public IP option. Then, select both your default security group and the security group that you created above for the VPN.
Click Launch instance
Step 3 — Disable Source/Destination Check
From the list of instances, select the VPN instance and then Actions -> Networking -> Change source/destination check from the drop down menu.
Select Stop and click Save. This is needed as otherwise, your VPN server will not be able to connect to your other AWS resources.
Step 4 — Create an Elastic IP Address
Overview: when an EC2 instance is stopped and restarted, the Public IP address changes. We want the IP address of our VPN server to remain static so we’ll use an Elastic IP Address.
From the E2C Dashboard, select Elastic IPs:
Click Allocate Elastic IP address:
Make a note of your new Elastic IP address as this will be the Public IP Address of your VPN server. We will refer to this address later as PUBLIC-IP-OF-VPN-SERVER.
Select the IP address you just created and click Associate Elastic IP address:
Then, select the Elastic IP and click Associate address from the drop down menu.
Select the EC2 instance you created above and click Associate:
Step 5— Install and Configure the OpenVPN Server
SSH into your VPN server:
$ ssh ubuntu@PUBLIC-IP-OF-VPN-SERVER
Download our helper scripts and set up a default config:
$ git clone https://github.com/redgeoff/openvpn-server-vagrant
$ cd openvpn-server-vagrant
$ cp config-default.sh config.sh
Edit config.sh and enter in your configuration. Note: PUBLIC_IP should be equal to the Elastic IP Address that you created above.
$ nano config.sh
Switch to root:
$ sudo su -
You’ll now update Ubuntu. Note: you will be prompted several times and when you do, just press the Enter key.
$ /home/ubuntu/openvpn-server-vagrant/ubuntu.sh
Now, install OpenVPN. Note: you will be prompted several times and when you do, just press the Enter key.
$ /home/ubuntu/openvpn-server-vagrant/openvpn.sh
At this point, the OpenVPN server is running.
Step 6 — Add the Route
Routes must be added to the server so that your team’s clients know which traffic to route to the VPN server.
You can determine the proper subnet by returning to your list of EC2 instances, clicking on a target instance and identifying the Private IP.
Your network will be the first 2 parts of the Private IP appended with zeros, e.g. 172.31.0.0
On the VPN server edit /etc/openvpn/server/server.conf and add something like the following:
push "route 172.31.0.0 255.255.0.0"
Then, restart the VPN server with:
$ systemctl restart openvpn-server@server.service
Step 7 — Grant Access to Your VPN
Note: We assume that you are still SSH’d into the VPN and logged in as root.
Run the following command and be sure to replace client below with a unique name for your user/client.
$ /home/ubuntu/openvpn-server-vagrant/add-client.sh client
You’ll then find a configuration file at
~/client-configs/files/client-name.ovpn
You will want to provide this file to the individual on your team who will be connecting to your VPN. SCP is handy for downloading this .ovpn file from your VPN server.
Your team can use one of various VPN clients such as Tunnelblick (OS X) and OpenVPN (Linux, iOS, Android and Windows). After installing one of these clients, they should be able to set up the VPN config just by double clicking on the .ovpn file.
Note: once connected to the VPN, your users will want to use the Private IPs of your AWS resources. You may want to use nslookup to lookup the IP address from the AWS custom domain names provided by AWS. You’ll probably want to use Route 53 to create subdomain records that route to the Private IPs.
Step 8 — Revoke Access to Your VPN
Note: We assume that you are still SSH’d into the VPN and logged in as root.
Run the following command and be sure to replace client below with a unique name for your user/client.
$ /home/ubuntu/openvpn-server-vagrant/revoke-full.sh client
Troubleshooting
If your VPN client reports a TLS handshake failed error then this is most likely because your VPN security group (Step 1) is incorrect. Make sure that you have the correct ports and protocols specified — a common problem is not specifying UDP for port 1194.