WireGuard is fast, simple and modern VPN protocol. In this article we are going to setup WireGuard VPN system, with server running on AWS Lightsail  &  few clients securely connected to server.

Here is top-level overview of the VPN system we are going to build in this article.

overview of wireguard server with clients as phone, pc, fire tv and other devices.
Overview - Objectives of this article
  1. Create AWS Lightsail instance with Ubuntu server.
  2. Configure WireGuard VPN Server.
  3. Configure Firewall rules on server.
  4. Setup Unbound DNS.
  5. Create three clients iPhone, Laptop/PC and Fire TV.
  6. Download configuration to client devices and connect.
You need linux machine to configure this whole VPN system, any Linux desktop would work or if you have windows 10 you can use windows subsystem for linux (WSL).

What is WireGuard?

WireGuard is an open-source simple and fast VPN implementation. It is VPN protocol designed to be simple, linear, fast and yet being most secure by implementing modern cryptography standards and algorithms.

WireGuard® is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography. It aims to be faster, simpler, leaner, and more useful than IPsec, while avoiding the massive headache. - wireguard.com

Why AWS Lightsail?

There are many cloud service providers, when it comes to pricing no one can beat pricing of AWS combined with simplicity of Lightsail, makes it preferred choice. You can get $5 machine with 2 TB bandwidth which is ideal for standard home scenario with 10 or fewer devices.

Microsoft's Azure is also good option but it is $$$ and bandwidth is limited to 5 GB per machine, which mean you have to pay more for additional data usage. Checkout following article for configuring WireGuard over Azure VM.

Setup WireGuard VPN Server in Azure Cloud
WireGuard [https://www.wireguard.com/] is an extremely simple, fast and modernopen-source Virtual Private Network (VPN) implementation. It is a VPN protocolbased on modern cryptographic technology. WireGuard uses state-of-the-art cryptography, like the Noise protocol framework[http://www.noiseprotocol.org…

1) Create AWS Lightsail Instance

The first thing we need to do is to set up AWS Lightsail instance and open required ports.

create lightsail instance for ubuntu server
Create Instance - Ubuntu server
configure incoming firewall ports for server machine
Configure Incoming firewall ports

We have opened two ports one for SSH connection and other one for VPN tunnel connection.

Lightsail allows in-browser ssh connection to host machine, in that case you don't really need to open port 22 for ssh. But I find it little slower, so I prefer initial configuration using ssh client on port 22 & subsequent updates with in-browser session.

For security reasons 51820/udp should be the only port open on your Lightsail instace.  You can delete the entry for tcp/22 once done with server setup.

2) Configure WireGuard Server

In this section we are going to configure Wireguard server instance, generate configuration files for clients and setup DNS to avoid DNS leak from clients.

We can toss all bash scripts in one file & fire in single shot, but that would defeat purpose; which is, to guide to through the process rather than giving you black-box.

If you are interested in single bash script for setting up wireguard server & generate clients, check this out

Setup Wireguard Server in one shot on Debian/Ubuntu
This is short article consist of bash script for creating WireGuard[https://www.wireguard.com/] server with listed clients in sigle shot. Beforerunning this script make sure: * Set your server’s public IP. * Update list of clients you need to generate. * Create bash file such as ‘wg-script.sh’…

If you are using Ubuntu server lower than 20.04 add following wireguard repo to your sources.

# add wireguard repo
sudo add-apt-repository ppa:wireguard/wireguard -y
Add WireGuard repository

First we need to install WireGuard, QR Encode & updates.

sudo apt update -y && 
sudo apt upgrade -y

# install wireguard
sudo apt install wireguard -y  

# Generate QR codes for configs.
sudo apt install qrencode -y

# if you are using Debian 10 (skip otherwise)
sudo apt install linux-headers-$(uname -r) && sudo reboot
Install WireGuard & other libraries

Now generate public & private keys for server and clients, that includes:

  • WireGuard Server
  • iPhone
  • Laptop
  • Fire TV
umask 077 && 
mkdir wg && 
mkdir wg/keys &&
mkdir wg/clients &&
wg genkey | tee wg/keys/server_private_key | wg pubkey > wg/keys/server_public_key
wg genkey | tee wg/keys/iphone_private_key | wg pubkey > wg/keys/iphone_public_key && 
wg genkey | tee wg/keys/laptop_private_key | wg pubkey > wg/keys/laptop_public_key &&
wg genkey | tee wg/keys/firetv_private_key | wg pubkey > wg/keys/firetv_public_key 
Create public/private keys for server & clients

2.1) Generate WireGuard Server Configuration

WireGuard uses 'wg0' as default terminology for network interface. We can generate WireGuard's network interface configuration & attach expected number of clients from the following bash script:

echo " 
[Interface]
PrivateKey = $(cat wg/keys/server_private_key)
Address = 10.200.200.1/24
ListenPort = 51820
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o ens3 -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o ens3 -j MASQUERADE; iptables -t nat -A POSTROUTING -s 10.200.200.0/24 -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o ens3 -j MASQUERADE; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -D POSTROUTING -o ens3 -j MASQUERADE; iptables -t nat -D POSTROUTING -s 10.200.200.0/24 -o eth0 -j MASQUERADE
SaveConfig = true 

#Clients
[Peer] # ihphone
PublicKey = $(cat wg/keys/iphone_public_key)
AllowedIPs = 10.200.200.2/32

[Peer] # laptop
PublicKey = $(cat wg/keys/laptop_public_key)
AllowedIPs = 10.200.200.4/32

[Peer] # fire-tv
PublicKey = $(cat wg/keys/firetv_public_key)
AllowedIPs = 10.200.200.6/32
"| sudo tee /etc/wireguard/wg0.conf
Generate WireGuard interface configuration

Now everything we need for server is configured. Following script will spin up WireGuard network interface and makes sure it is auto start on reboot.

# bring the Wireguard interface up
sudo wg-quick up wg0 &&  
sudo systemctl enable wg-quick@wg0.service
Spin up WireGuard interface

2.2) Enable IP Forwarding

We need to enable IP forwarding in order to correctly route the traffic between clients, server & internet.

# enable IPv4 forwarding
sudo sed -i 's/\#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/g' /etc/sysctl.conf
# negate the need to reboot after the above change
sudo sysctl -p
sudo echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
IP Forwarding

2.3) Configure Firewall

The next step is to configure firewall rules. Iptables is small useful utility on linux systems, used to configure firewall rules.

# Track VPN connection
sudo iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

# Enable VPN traffic on the listening port: 51820
sudo iptables -A INPUT -p udp -m udp --dport 51820 -m conntrack --ctstate NEW -j ACCEPT

# TCP & UDP recursive DNS traffic
sudo iptables -A INPUT -s 10.200.200.0/24 -p tcp -m tcp --dport 53 -m conntrack --ctstate NEW -j ACCEPT
sudo iptables -A INPUT -s 10.200.200.0/24 -p udp -m udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT

# Allow forwarding of packets that stay in the VPN tunnel
sudo iptables -A FORWARD -i wg0 -o wg0 -m conntrack --ctstate NEW -j ACCEPT
Setup Firewall rules

These iptables-based firewall rules are in memory and gets wiped out on reboot. In order to make these rules persistent we need iptables-persistant library to be installed. Run following bash script, to install and configured persistence for firewall rules.

# make firewall changes persistent
sudo apt install iptables-persistent -y &&
sudo systemctl enable netfilter-persistent &&
sudo netfilter-persistent save
Firewall rules persistence

2.4 Configure DNS (Optional)

This is by far the most important step in terms of privacy & security. You need to configure DNS on the VPN server to avoid DNS leaks.

Although this is optional, but I would strongly recommend configuring your own DNS.

We are going to use Unbound DNS, for our case. Run each script in different steps as commented for each section.

# install Unbound DNS
sudo apt install unbound unbound-host -y

# download list of DNS root servers
sudo curl -o /var/lib/unbound/root.hints https://www.internic.net/domain/named.cache

# create Unbound config file
echo "
server:
    num-threads: 4
    # enable logs
    verbosity: 1
    # list of root DNS servers
    root-hints: \"/var/lib/unbound/root.hints\"
    # use the root server's key for DNSSEC
    auto-trust-anchor-file: \"/var/lib/unbound/root.key\"
    # respond to DNS requests on all interfaces
    interface: 0.0.0.0
    max-udp-size: 3072
    # IPs authorised to access the DNS Server
    access-control: 0.0.0.0/0                 refuse
    access-control: 127.0.0.1                 allow
    access-control: 10.200.200.0/24             allow
    # not allowed to be returned for public Internet  names
    private-address: 10.200.200.0/24
    #hide DNS Server info
    hide-identity: yes
    hide-version: yes
    # limit DNS fraud and use DNSSEC
    harden-glue: yes
    harden-dnssec-stripped: yes
    harden-referral-path: yes
    # add an unwanted reply threshold to clean the cache and avoid, when possible, DNS poisoning
    unwanted-reply-threshold: 10000000
    # have the validator print validation failures to the log
    val-log-level: 1
    # minimum lifetime of cache entries in seconds
    cache-min-ttl: 1800
    # maximum lifetime of cached entries in seconds
    cache-max-ttl: 14400
    prefetch: yes
    prefetch-key: yes

" | sudo tee /etc/unbound/unbound.conf 

# give root ownership of the Unbound config
sudo chown -R unbound:unbound /var/lib/unbound
Install & Configure Unbound DNS

One last piece of puzzle is before enabling DNS, is to add your hosts name to '/etc/hosts' file:

hostname
# output: your_host_name

# add hostname
sudo nano /etc/hosts
#27.0.0.1 localhost your_host_name
Update hosts file

The final step in DNS configuration is to disable systemd-resolved and enable Unbound DNS & unbound-resolved.

# disable systemd-resolved
sudo systemctl stop systemd-resolved &&
sudo systemctl disable systemd-resolved

# enable Unbound in place of systemd-resovled
sudo systemctl enable unbound-resolvconf &&
sudo systemctl enable unbound

sudo reboot
Enable Unbound DNS & reboot

To check, if DNS is configured correctly you can run 'nslookup' for example.

nslookup xalitech.com
#ouput:
#Server:	10.200.200.1
#Address:	10.200.200.1#53

#Non-authoritative answer:
#Name:	xalitech.com
#Address: 3.229.159.31
Verify DNS 

2.5) Generate Client Configurations

Since the public & private keys for clients are already generated and attached to server, it is time generate configuration files for clients.

If you didn't configure DNS in previous section you can simply put your preferred DNS IP  in following configurations. For example, you can replace "DNS = 10.200.200.1" with Cloudflare's DNS "DNS = 1.1.1.1".

Get public IP of your machine (Lightsail instance) and export it in your terminal session, variable ${serverIP} will be used in following client configurations.

# Public IP of Lightsail instance
export serverIP="54.166.184.7"
Set public IP for configuration

Generate config file for iPhone and create corresponding QR Code image.

echo "[Interface] 
Address = 10.200.200.2/32
PrivateKey = $(cat 'wg/keys/iphone_private_key')
DNS = 10.200.200.1 

[Peer]
PublicKey = $(cat 'wg/keys/server_public_key')
Endpoint = ${serverIP}:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 21" > wg/clients/iphone.conf &&
qrencode -o wg/clients/iphone.png -t png < wg/clients/iphone.conf 
iPhone's configuration & QR Code image

Generate configuration file to be used on laptop or pc.

echo "[Interface] 
Address = 10.200.200.4/32
PrivateKey = $(cat 'wg/keys/laptop_private_key')
DNS = 10.200.200.1 

[Peer]
PublicKey = $(cat 'wg/keys/server_public_key')
Endpoint = ${serverIP}:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 21" > wg/clients/laptop.conf  
Laptop/PC configuration

Generate configuration file for Fire TV client.

echo "[Interface] 
Address = 10.200.200.6/32
PrivateKey = $(cat 'wg/keys/firetv_private_key')
DNS = 10.200.200.1 

[Peer]
PublicKey = $(cat 'wg/keys/server_public_key')
Endpoint = ${serverIP}:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 21" > wg/clients/firetv.conf  
Fire TV configuration

Although we have configured three devices but you can add as many as you want.

When it comes to adding clients to WireGuard, the sky is unlimited but bandwidth is not. So be mindful before being too generous to your friends and family by give them free vpn access, you would only get 2TB bandwith with sindle Lightsail instance.

Now everything on server is configured, it is time to download clients configurations & connect your devices to server.

3) Configure Client Devices

Now use your laptop or pc to configure clients. Create 'wg' folder inside home directory & download all client configurations to your laptop/pc.

# Download all configurations from server.
scp your_server_login@54.166.184.7:wg/clients/* wg/
Download configuration files from server to your PC

3.1) Setup iPhone

Download & install WireGuard app from App Store. Tap on "add" icon & select "Create from QR Code". Open iphon.png & scan QR Code.

wireguard iphone app - add tunnel options
WireGuard - Add Tunnel

When  you enable VPN tunnel there should be little vpn sign on top of screen. If you tap on view log  you should see communication with your VPN server, for example a bunch of 'handshake' & 'keep alive' statements.

wireguard iphone app settings and view log
WireGuard iPhone App - Settings

3.2) Setup laptop or PC

We are going to configure Linux-based desktop machine. This example shows Ubuntu/Debian based configuration but it is applicable to any Linux distro. Now open bash terminal on your laptop/pc (not server) & create configuration file for network interface 'wg0-client'.

Download configuration file generated for laptop from vpn server to your laptop:

sudo scp vpn-server-login@vpn-server-ip:wg/clients/laptop.conf /etc/wireguard/wg0-client.conf
Download laptop configuration file from server

Install WireGuard client on your machine:

add-apt-repository ppa:wireguard/wireguard &&
apt-get update &&
apt-get install wireguard-dkms wireguard-tools linux-headers-$(uname -r)
Install WireGuard Client

Enable WireGuard network interface & set it to auto enable on reboot.

sudo wg-quick up wg0-client && 
sudo systemctl enable wg-quick@wg0-client.service
Enable WireGuard client interface

Now your network traffic from local machine is going through VPN tunnel  of your own VPN server. A quick way to check is the following command.

sudo wg-quick show

#interface: wg0-client
#  public key: EJyWydpW7y7i2OEG4X3qbjsBXDZK2gwrb/UHCeyceQE=
#  private key: (hidden)
#  listening port: 37085
#  fwmark: 0xca6c

#peer: nhBYGzGPV27EP/REDTpyJ6i1hEvhTN45wN0MCrqqVW4=
#  endpoint: <IP_Lightsail-Instance>:51820
#  allowed ips: 0.0.0.0/0
#  latest handshake: 40 seconds ago
#  transfer: 137.38 MiB received, 11.58 MiB sent
#  persistent keepalive: every 21 seconds
Status Check

3.3) Setup Fire TV Client

The first thing you need is to download and install WireGuard app on Fire TV. Unfortunately, WireGuard app is not available at the time of writing this blog post.

Fortunately we have workaround, through which we can download and install WireGuard on Fire TV.

Connect your laptop or pc to the same Wi-Fi /network as Fire TV. We are going to download WireGuard app binary to the laptop and push the installation from laptop to Fire TV.

  • Download the latest WireGuard .apk file from F-Driod & rename it to something short like "wireguard.apk" and copy to your home folder.
  • Get IP of your Fire TV from:  Home > Settings > My Fire TV > About > Network
  • Enable ADB Debugging from : Home > Settings > My Fire TV > Developer Options > ADB debugging

Install  WireGuard app

sudo apt install adb
Install adb
adb connect <firetv-ip>:5555
Connect to Fire TV
sudo adb install ~/wirguard.apk
Install WireGuard on Fire TV

Now your WireGuard app is installed. There is little  glitch in finding the app from pile of some many apps on your home screen.

Go to: Home > Settings > Applications > Manage Installed Applications > Launch WireGuard. Copy firetv.conf file via USB or network shared. Open WireGuard app an add configuration file.

Don't forget to turn-off ADB debugging once you are done with setup.

You can try some stream and see if every thing is working as expected & also you can check on the server to see if there is any traffic from Fire TV client.

Summary

WireGuard is great open-source VPN technology which is secure and fast, and yet simple. VPN is essential service for modern day world where more and more things are done online ranging from social media, shopping and other services.

The main objective of this article is to provide way to secure your location, identity, and internet traffic. With little technical knowledge you can have your own VPN server which is more economical than shopping for commercial service for VPN.

There are a number of commercial VPN provides which can be used but there are few problems with that.

Firstly you need to sign up for service by giving your personal info & Credit Card etc, the first rule of privacy is already broken.  

Secondly, although internet traffic between you and their server is secured, but they know what your internet habits & keep log of your activity for short period. Lastly, every now, and then we get to hear about data breaches by vpn providers such as NordVPN Data breach.

So having your own VPN service is better if you consider all aforementioned concerns, the only thing you need to do one in while to install updated on server.

Hope you enjoyed the article!

Useful resources: