WireGuard is a new VPN that got a bit of a buzz lately. It claims to be faster, simpler, and leaner than it's competitor, IPSec, and OpenVPN. You can read all about it on the official homepage: https://www.wireguard.com/
In the following sections, we're going to install WireGuard on an Amazon Lightsail virtual server and install the WireGuard Android app on a smartphone. This is one use case of a VPN to hide network traffic from an ISP. This is especially useful for mobile devices when you are connecting to public internet access points, such as hotels. All they see is a connection to the VPN server but nothing else.
Another use case of a VPN, especially for companies, is connecting local networks of remote offices to the main company network. A VPN allows them to connect these two local networks over the public Internet securely. A company can also use a VPN for employees that work at home to allow them to connect to the internal network securely.
WireGuard can be used for all these use cases. WireGuard runs on Linux, Windows, FreeBSD, OpenBSD, macOS, iOS, and Android.
Lightsail is Amazon's answer to all the cheap VPS providers. It provides virtual servers that run on Amazon EC2. You don't have to be familiar with EC2. Amazon makes it very simple to set up a virtual server with a web interface.
Prices start at USD 3.50 and go up to $160 per month depending on the CPU, RAM, SSD, network data transfer, and operating system. Visit the pricing page to learn more: https://aws.amazon.com/lightsail/pricing/
Lightsail supports Linux and Windows-based virtual servers. Windows servers cost a bit more because of the additional license they have to pay Microsoft.
For this setup, we create a Linux VPS and choose the cheapest server for $3.50. The first month is free, so it's a great way to test these servers.
If you want to follow this tutorial, you need an Amazon account. To sign up, you can go to https://aws.amazon.com/ and click on the "Sign Up" button.
Go to https://lightsail.aws.amazon.com and sign in with your Amazon account. Click on Create instance.
First, you need to select the Region and Availability Zone, where Amazon should create your new virtual server.
Next, select the operating system. We don't need any pre-installed applications, just a plain operating system. I select Debian 9.5, which is one of the operating systems that WireGuard supports. Check the WireGuard install page for more information: https://www.wireguard.com/install/
Next, we create a public/private key for connecting to the server with SSH. On your local computer run this command:
ssh-keygen -N "mysupersecretpassphrase" -t rsa -b 4096 -C "mydesktopcomputer" -f lightsail
The passphrase (string after
-N) protects your private key. Replace it with something else! This command creates two files in the current directory, a public key (lightsail.pub), and a private key (lightsail).
On the server creation page click on "Change SSH key pair"
then "Upload New"
select the public key file (lightsail.pub) and upload the key.
Lastly, choose the instance plan. The cheapest server is powerful enough for just running WireGuard.
Click "Create" and wait about a minute, while Amazon is preparing and starting your virtual server. By default, Lightsail virtual servers get a new IP address each time you reboot them. However, what we want is a static IP address that never changes. A static IP address for your server is included in the monthly fee.
After your VPS is running, click on the "Networking" tab and create a static IP address.
Attach your instance to this static IP address and click "Create"
The website should now show you the static IP address for your server.
Click on the name of your instance. In my case, "Debian-512MB-Virgina-1". This opens the configuration page for a specific instance.
Here we need to add a new firewall rule. Click on "Networking and "Edit rules".
Delete the HTTP TCP 80 rule. We don't run a web server on this server and add a new UDP rule. You can choose any free port you want. Usually, I pick a port between 32768 - 65535. For this blog post, I'm going to use port 54321.
That concludes the configuration of our virtual server. You can close the website, and we're going to continue on the command line.
Install required packages
Connect to the server with SSH.
ssh -i lightsail firstname.lastname@example.org
-i specifies the path to the private key file. SSH asks you for the private key passphrase, and when everything is correct, connect you to your new virtual server.
First, we make sure that all installed packages are up to date.
sudo -i apt update apt dist-upgrade
Next, we install all the required packages for this tutorial: WireGuard, unbound (DNS server), and qrencode.
echo "deb http://deb.debian.org/debian/ unstable main" > /etc/apt/sources.list.d/unstable.list printf 'Package: *\nPin: release a=unstable\nPin-Priority: 90\n' > /etc/apt/preferences.d/limit-unstable apt update apt install wireguard unbound qrencode curl
Next we need to enable IP Forwarding. Open
/etc/sysctl.conf and search for the line
#net.ipv4.ip_forward uncomment this line by removing the
# at the beginning. It should look like this:
Lastly, we do some clean-up and remove unused packages
Set up WireGuard
WireGuard is using public/private key cryptography. For that, we need to create a public/private key pair for each participant of the VPN. In this setup, we have the server and one Android phone, so we create two key pairs.
cd /etc/wireguard/ umask 077 wg genkey | tee server_private.key | wg pubkey > server_public.key wg genkey | tee client_private.key | wg pubkey > client_public.key
Create the file
and insert the following text
[Interface] Address = 192.168.2.1 PrivateKey = server_private_key ListenPort = 54321 SaveConfig = false PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; iptables -A INPUT -s 192.168.2.0/24 -p udp -m udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; iptables -D INPUT -s 192.168.2.0/24 -p udp -m udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT [Peer] PublicKey = client_public_key AllowedIPs = 192.168.2.2/32
ListenPort, you need to use the same port number that you specified in the UDP firewall rule on the Lightsail configuration page. This is the port where WireGuard is listening for incoming VPN connections.
Save the file and close Nano. Next we replace the string
client_public_key with the content of the files.
sed -i "s/server_private_key/$(sed 's:/:\\/:g' server_private.key)/" wg0.conf sed -i "s/client_public_key/$(sed 's:/:\\/:g' client_public.key)/" wg0.conf
Check the wg0.conf file
It should look similar to this.
[Interface] Address = 192.168.2.1 PrivateKey = cMgbJqIl6CuU6U6gpXu4TwUlJ+TnAgaSa6Dc8b5g1F8= ListenPort = 54321 ... [Peer] PublicKey = GXehejiGNxfOk5bEKECYgQg0nM9cu80BxPJap47s3QE= AllowedIPs = 192.168.2.2/32
Set up a DNS server
Next, we configure the DNS server
unbound. This server is going to answer all DNS queries from the VPN clients.
I use the configuration described in this WireGuard article:
curl -o /var/lib/unbound/root.hints https://www.internic.net/domain/named.cache chown -R unbound:unbound /var/lib/unbound cd /etc/unbound/unbound.conf.d nano unbound_srv.conf
Insert the following text into the editor
server: num-threads: 4 verbosity: 1 root-hints: "/var/lib/unbound/root.hints" interface: 0.0.0.0 max-udp-size: 3072 access-control: 0.0.0.0/0 refuse access-control: 127.0.0.1 allow access-control: 192.168.2.0/24 allow private-address: 192.168.2.0/24 hide-identity: yes hide-version: yes harden-glue: yes harden-dnssec-stripped: yes harden-referral-path: yes unwanted-reply-threshold: 10000000 val-log-level: 1 cache-min-ttl: 1800 cache-max-ttl: 14400 prefetch: yes prefetch-key: yes
Save the file and exit Nano, restart the process, and enable it, so it automatically starts each time you boot the server.
systemctl restart unbound systemctl enable unbound
Check if the service is running. You should see a green
active (running) text.
systemctl status unbound
After setting everything up, we reboot the server
The reboot closes your SSH connection. Reconnect
ssh -i lightsail email@example.com
unbound is running
sudo -i systemctl status unbound
Now we start the WireGuard
wg0 network interface and enable it, so Linux automatically creates the interface each time we boot the server.
wg-quick up wg0 systemctl enable firstname.lastname@example.org
When you enter
ifconfig you should see the WireGuard interface
wg0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 inet addr:192.168.2.1 P-t-P:192.168.2.1 Mask:255.255.255.255 UP POINTOPOINT RUNNING NOARP MTU:8921 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
If you want to connect from an Android phone to a WireGuard server, you need to install the WireGuard app from the play store:
Next, we need to create a new configuration in the app. We can do this either from scratch by entering all the information manually or by importing a file. In this tutorial, we're going to use the third option and create the configuration file on the server, display a QR code, and then scan the QR code with the app.
First, we create the configuration file. I call it
client2 in this example.
cd /etc/wireguard/ nano client2
Paste the following text into the editor.
[Interface] Address = 192.168.2.2/32 PrivateKey = client_private_key DNS = 192.168.2.1 MTU = 1280 [Peer] PublicKey = server_public_key Endpoint = 18.104.22.168:54321 AllowedIPs = 0.0.0.0/0 PersistentKeepalive = 25
Make sure that the
Endpoint points to the static IP address of your virtual server. Port must be the same as
ListenPort in the
wg0.conf file. If you have multiple clients, you need to make sure that
Address is free and not already assigned to another client.
Next we replace the strings
server_public_key with the real keys.
sed -i "s/client_private_key/$(sed 's:/:\\/:g' client_private.key)/" client2 sed -i "s/server_public_key/$(sed 's:/:\\/:g' server_public.key)/" client2
Run the following command to display the QR code of the
client2 file content.
qrencode -t ansiutf8 < client2
Open the WireGuard app on your Android phone, click on the + button, select "Create from QR code", and then point the camera to the QR code on your screen. If the app was able to scan the code successfully, it asks for a tunnel name. Enter a name and tap on "Create tunnel".
Enable the tunnel with the slider. You should see a key icon at the top of your screen.
To check if the VPN works, open a browser and go to the URL: https://www.whatismyip.com/
Alternatively, enter the search term "my ip" into the Google search.
If the connection is routed through the VPN, it should show the IP address of the virtual server as the public address.
To check if DNS requests are routed through the VPN, go to https://www.dnsleaktest.com and run the extended test. The test runs for a few seconds and displays a list of servers that answered the DNS queries. Make sure that this list only contains your Lightsail server.
Read this guide about DNS leaks to learn more why you want to test for DNS leaks and it also shows you other methods for preventing leaks.
If you want to connect more clients, you repeat the client configuration.
- Create public/private key pair
- Create a client configuration file. Make sure
Addressis not already assigned.
- Add a new
[Peer]section to wg0.conf
- Restart wg0 interface.
wg-quick down wg0 && wg-quick up wg0
- Display the QR code and scan it with the app.
In this blog post, I showed how to connect an Android device to the WireGuard server. If you want to connect a Linux or macOS computer to the VPN, you find many tutorials on the WWW. Here a few links:
The following link points to an interesting article about
unbound. Especially the part about ad blocking could be useful for this set up when we connect with mobile devices to the VPN. If you are on a limited data plan, this could save some bandwidth.