Quick VPN setup with AWS Lightsail and Wireguard
How to run your own VPN in the cloud for less than a penny per hour ( $0.007 / hr )
Let’s talk about VPN’s
When consumer VPN’s hit the mainstream 8-10 years ago (I’m talking about things like Mulvad/Nord/etc..) it amazed me how many people (including some smart people I know and work with) jumped on the bandwagon because they didn’t want their ISP spying on their traffic. When I asked them why they felt the anonymous VPN operator was more trustworthy than a regulated ISP in the United States the response was usually a long pause; They had not considered that it was possible for the VPN operator to do the exact same thing. Anyways, I digress.
So let’s say you want to tunnel traffic through another country to test your service or hide your traffic through another server for some other reason. I’m assuming you’re doing legal things here and not going to get into the more rigorous details of OPSEC, dns leakage, or chained connections. I’m also not going to talk about alternatives like leveraging proxy servers via things like Shadowsocks or reverse ssh tunnels. It can get complex quick and everything is tradeoffs.
You need two things. A remote server and a wireguard connection.
Hosting
AWS has a service called Lightsail. It is a quick and easy way to stand up a server without some of the complexities (and options) that EC2 provides. Similar services are offered by the big cloud providers like Google’s GCP or Micrsoft’s Azure and a bunch of other platforms like DigitalOcean, Linode, Vultr, Hetzner, OVH, and Scaleway. Which one you use is up to you and involves lots of tradeoffs that are beyond the scope of this article.
A Secure Tunneling Protocol
Wireguard has been around for a few years now but is still relatively “new” to a lot of people. I heard about it back in 2018 and remember the awe at how quickly the connection established and how performant it was with limited resources. Way better than the IPSec / L2TP stuff I had been using. Linus finally picked it up back in early 2020 and since then adoption has been slowly happening with teams like Tailscale leading the way and layering in user friendly authentication/authorization that the wireguard protocol natively lacks. Pritunl and Zerotier have also added support and it powers Cloudflare’s WARP.
Sidebar - I was working at Netflix in 2019/2020 and got pinged for some help with a previsualization team on one of our partner managed shows that wanted to do remote multiuser editing. Partner managed means they make the movie and send it to Netflix which puts it on the service. So we didn’t usually get involved in the project execution, but I was part of a specialized group of which a small part of our remit was sort of like the A team. Come in, solve problems others can’t, and leave. It wasn’t exactly within my job description (I was leading and growing a engineering team building out the infrastructure for the then nascent Animation Studio) but I had done this stuff before, enjoy challenges and I love helping people.
I set them up with Tailscale (who was brand new on the scene) and gave them a script similar to this one to run in their own AWS account to run Unreal’s MultiUserEditing server on Linux. I shared it with Epic which resulted in some uncredited press and sharing of my guide/code on how to set it up. The folks at Tailscale though it was a pretty interesting use case and I knew from our initial meetings their product had a very high chance of long term success.
Let’s Set it up
There are a lot of tutorials out there on this stuff but I’m going to assume you know your way around a terminal and are fairly experienced. So here’s are the basic steps and some code I cobbled together (github repo here)
Requirements
Have an AWS Account, installed the aws cli and configured it with auth credentials.
Generate a pub/private keypair
Wireguard Client
Download the wireguard client and configure a new Tunnel. You will need the public key to copy to the server you setup in the next step. And you will need to swap out the server pub key and ip:port with your servers once it is setup.
LightSail setup
#!/bin/zsh
KEYPAIRFILE='~/.ssh/id_rsa.pub'
KEYPAIRNAME=$(basename -s '.pub' ${KEYPAIRFILE})
MACHINENAME='wg001'
OS='ubuntu_22_04'
PORT='41194'
REGION='ap-south-1'
# upload keypair
aws lightsail import-key-pair \
--region ${REGION} \
--key-pair-name ${KEYPAIRNAME} \
--public-key-base64 $(base64 -i ${KEYPAIRFILE})
# Get the cheapest bundle
CHEAPBUNDLE=$(echo `aws lightsail get-bundles --query 'bundles[0].bundleId' --region ${REGION} --output text` | tr -d '"')
echo "Found the cheapest bundle ${CHEAPBUNDLE}"
# Create the instance
echo "Creating the instance"
aws lightsail create-instances \
--instance-names ${MACHINENAME} \
--region ${REGION} \
--availability-zone ${REGION}a \
--blueprint-id ${OS} \
--bundle-id ${CHEAPBUNDLE} \
--key-pair-name ${KEYPAIRNAME}
# Wait a minute then grab the IP
EXTERNALIP=$(aws lightsail get-instance-access-details --instance-name ${MACHINENAME} --query 'accessDetails.ipAddress' --output text)
# Configure Lightsail Firewall.
# Can also use `open-instance-public-ports --port-info` if you want to add to the rules not remove the defaults
echo "Configuring Fireall"
aws lightsail put-instance-public-ports \
--instance-name ${MACHINENAME} \
--region ${REGION} \
--port-infos '[{"fromPort": 41194, "toPort": 41194, "protocol": "udp"}, {"fromPort": 22, "toPort": 22, "protocol": "tcp"}]'
# Print out the IP so we can ssh to it
echo "Ready to connect to ${EXTERNALIP}"
Wireguard Setup
make sure to copy over your public key from your client into the server’s Peer config section.
You’ll also need to grab the servers publickey to copy into your local clients config.
#!/bin/zsh
# ssh and configure wireguard
ssh ubuntu@$EXTERNALIP
sudo apt update -y && sudo apt install wireguard -y
sudo -i
mkdir -m 0700 /etc/wireguard/
cd /etc/wireguard/
umask 077; wg genkey | tee privatekey | wg pubkey > publickey
ETHINT=`ip a | grep enp | awk '{print $2}' | cut -d":" -f1`
SRVRIP="10.99.99.1"
ALLOWEDIPS="10.99.99.0/24"
PEERPUBKEY='GET THIS FROM YOUR WIREGUARD CLIENT'
tee /etc/wireguard/wg0.conf <<EOF
[Interface]
Address = $SRVRIP/24
ListenPort = 41194
PrivateKey = $(cat privatekey)
PostUp = iptables -t nat -A POSTROUTING -o $ETHINT -j MASQUERADE; ip6tables -t nat -A POSTROUTING -o $ETHINT -j MASQUERADE
PostDown = iptables -t nat -D POSTROUTING -o $ETHINT -j MASQUERADE; ip6tables -t nat -D POSTROUTING -o $ETHINT -j MASQUERADE
[Peer]
PublicKey = $PEERPUBKEY
AllowedIPs = $ALLOWEDIPS
EOF
ufw allow 41194/udp
ufw status
echo 'net.ipv4.ip_forward=1' | sudo tee -a /etc/sysctl.d/10-wireguard.conf
echo 'net.ipv6.conf.all.forwarding=1' | sudo tee -a /etc/sysctl.d/10-wireguard.conf
sysctl -p /etc/sysctl.d/10-wireguard.conf
systemctl enable wg-quick@wg0
systemctl start wg-quick@wg0
systemctl status wg-quick@wg0
wg
ip a show wg0
#You will need the public key for your client setup
echo "Setup Complete. Public Key Below. Please use this in your client config\n"
cat publickey
That’s it!
Bring your local connection up and you should have a full tunnel wireguard server tunneling your traffic through a different part of the world.
While the bundle I selected as part of the Lightsail setup was the cheapest (~$5 a month) you only get charged when it’s running. So don’t forget to stop it or delete it. May only cost you a few cents per month ($5/720 = $0.007/hr)
aws lightsail delete-instance --region ${REGION} --instance-name ${MACHINENAME}
aws lightsail stop-instance --region ${REGION} --instance-name ${MACHINENAME}
But wait…there’s more
Obviously I glossed over a lot of things here. Like maybe move the port to a less common one than 41194. Or maybe add a firewall rule to only allow traffic from your IP. And of course make sure your pub/private keys have a passphrase. And a whole lot of other stuff. Or streamlining it all into some local commands that do it all automagically on the fly by piping values around between the various scripts. But hopefully it’s a good skeleton to launch from. Happy VPN’ing.
Did this help you? Subscribe, Share, and/or buy me a coffee
Cute, but that doesn't give you any added privacy, so why bother?
The value of VPNs is having your data mixed in with other users data, and being hidden in the noise.