AWS OpenVPN That’s Actually Free

OpenVPN Community is a free open source VPN solution, but no one told AWS this. Or they just glossed over that whole section of their website. I’m sure I’m not the only one that has had a visceral reaction when going to set up a “community” OpenVPN server from one of the marketplace AMI’s or AWS’s own VPN where they charge you a user subscription and hourly usage fee that cost a magnitude more than the EC2 instance you’re installing it on.
Well, up with that I will not put. Here’s how to set up OpenVPN on an Ubuntu AMI. Stick it on a t3.micro instance and enjoy the feeling of having a VPN without parasites attached.
Step 1) Launch an Instance
You can choose whatever instance type you think will suite your needs here, it’s largely going to depend on what your network throughput as smaller instance types have limited network and the number of users. If it’s slow, it’s easy to change. 20gb of gp3 storage should be plenty, the vpn logs aren’t that big. This guide was working with the latest AWS provided Ubuntu AMI at the time of writing.
Create a VPN Security Group for this instance that allows UDP inbound to port 1194. You can also use this security group as the allow rule source to access other resources in account.
Step 2) Install OpenVPN
You’ll need the openvpn and easyrsa packages, both can be installed via apt.
sudo apt update
sudo apt install -y openvpn easy-rsa
Step 3) Generate Certificates
OpenVPN needs a number of certificates and keys to function. These are generated with easy-rsa. Before we do this though we’re going to copy easy-rsa someplace where it will generate those certificates and keys into someplace more standadized.
sudo mkdir /etc/openvpn/easy-rsa
cd /etc/openvpn/easy-rsa
sudo cp -R /usr/share/easy-rsa/* /etc/openvpn/easy-rsa/
Next, generate the certs and keys. If you want the added security you can remove the nopass flag. For <server> you can use any identifiable name, “server” will work or you could use the machine hostname.
cd /etc/openvpn/easy-rsa
sudo ./easyrsa init-pki
sudo ./easyrsa build-ca nopass
sudo ./easyrsa gen-req <server> nopass
sudo ./easyrsa sign-req server <server>
sudo ./easyrsa gen-dh
Next we generate a client certificate. This is the certificate the user will be using so I would suggest naming it for the user or service account.
sudo ./easyrsa gen-req <user> nopass
sudo ./easyrsa sign-req client <user>
Certificates will be generated into the following locations:
Server Cert and Key *
/etc/openvpn/easy-rsa/pki/issued/<server>.crt
/etc/openvpn/easy-rsa/pki/private/<server>.crt
Client Cert and Key **
/etc/openvpn/easy-rsa/pki/issued/<user>.crt
/etc/openvpn/easy-rsa/pki/private/<user>.crt
Certificate Authority Cert ***
/etc/openvpn/easy-rsa/pki/ca.crt
* The server cert and key are used in the openvpn server.conf
** The client cert and key are used in the clients openvpn config file.
*** The CA certificate is used in both the server and client configs.
Step 4) Create the OpenVPN Server Config
Use the following template and create the file at /etc/openvpn/server.conf
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
topology subnet
server 10.8.0.0 255.255.255.0
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 172.31.0.2"
push "route 172.31.0.0 255.255.0.0"
ifconfig-pool-persist ipp.txt
keepalive 10 120
persist-key
persist-tun
status /var/log/openvpn/openvpn-status.log
log-append /var/log/openvpn/openvpn.log
verb 3
explicit-exit-notify 1
Change the <pvc cidr range> to your private pvc range. You can add additional lines here if you have multiple ranges defined. The default is 172.31.0.0/16.
Change the <dns ip> to whatever the ip of the cide ending in .2. For example 172.31.0.2. The .2 ip is always reserved by AWS for their internal DNS resolver. This will allow you to resolve host names at .internal and amazonaws.com to their internal ip when connected to the VPN.
Step 5) Setup Networking
Before we start the vpn server we need to set up ip masquerading and some additional iptables rules that most guides miss. You’ll want to check what your primary network interface is using ifconfig and update these rules accordingly. My interface was named ens5 however it might also be eth0 depending on what instance type was chosen.
sudo echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
sudo iptables -A INPUT -i ens5 -m state --state NEW -p udp --dport 1194 -j ACCEPT
sudo iptables -A INPUT -i tun+ -j ACCEPT
sudo iptables -A FORWARD -i tun+ -j ACCEPT
sudo iptables -A FORWARD -i tun+ -o ens5 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -i ens5 -o tun+ -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o ens5 -j MASQUERADE
sudo iptables -A OUTPUT -o tun+ -j ACCEPT
For more information on what each of these rules do see: https://arashmilani.com/post?id=53
Step 6) Start the OpenVPN Server
sudo systemctl enable [email protected]
sudo systemctl start [email protected]
sudo systemctl status [email protected]
Troubleshooting Tip
If there the server is not starting, check the logs at /var/logs/openvpn/openvpn.log. You can increase the log verbosity by adjusting the verb variable in the server.conf file. 9 is the highest.
Step 7) Configure Client
Download the OpenVPN client. Don’t use a client packaged with your OS, it may not work.
https://openvpn.net/community-downloads/
Use the following template to create a client.ovpn file. This file should then be placed in the correct directory for your OS see: https://openvpn.net/community-resources/creating-configuration-files-for-server-and-clients/
Download the certificate authority cert and the client key and certificate into the same directory as the config.
Update the ip address and cert/key names in the config.
client
remote <ip or hostname of the ec2 instance> 1194
route-nopull
dev tun
proto udp
resolv-retry infinite
nobind
persist-key
persist-tun
ca <ca key filename>
cert <client cert filename>
key <client cert key name>
remote-cert-tls server
verb 3
Now just click connect and breathe a sigh of relief that you’re not paying a monthly subscription per user for a shell script that generated some configs for you.