Configuring an open source VPN with Wireguard

September 09, 2024

vpn-cover

In the last days of August 2024, the searchs for VPNs on Google from Brazil suddenly jumped (and decreased in a few days). The reason was the block of X.com nationwide after not following the demands from the Brazilian court. This post is not about this block, but the use of VPNs.

google-trends

Using a VPN is highly recommended to protect your privacy. When you connect to a VPN, all requests from your computer don't reach the destination directly, they are encrypted and sent to an intermediary server; then, the request is redirected from the server to the final destination.

This way, your computer's address is not visible by the target website, and the intermediary server's is. This helps with anonymity and also prevents you from geographic targeting if you use a VPN server in another country (some websites have rules based on IP geolocation).

It is also useful when connecting from untrusted networks, like from airports, restaurants and public places. The network's administrator can't know what is the target of the request, since it isn't going to a known target like social networks or banks, but the VPN server's IP.

In addition to the paid and famous options, there are free VPN providers, but their use is discouraged since your requests can be tracked and analysed in order to make the service profitable in another way.

It is also possible to setup a VPN server by your own, and it is the focus of this post. This may even be more economically viable and provide guarantees that there is no one in the middle observing your requests.

Getting started

There are some steps to get it running:

  • You need a server: cloud, VPS, or any machine with public IP;
  • do some steps on the server to install and configure Wireguard;
  • configure your local device to use the remote server as proxy.

Getting a server

I won't deep dive on this subject since it could take much space of this post and it isn't the focus. But in short words, you can get a server from free tiers on Google or Oracle and use credits from AWS, Azure, DigitalOcean, Vultr...

Of course, you can still be tracked because Cloud's IP ranges are widely known. But since I'm presuming you're about to use VPNs for good reasons (privacy), this won't be a problem.

You still have safe and privacy-focused options for VPS hosting that allow you to pay in crypto without identifying yourself. You can find some options with a brief research.

Configuring the server

This tutorial will explain how to use https://www.wireguard.com/, one of the existent open source VPN options. I'm sticking with it because of its simplicity and greater performance compared to OpenVPN, another open source alternative.

Basic setup

The steps start by installing wireguard:

sudo apt-get update -y
sudo apt-get install wireguard -y

After this, you will have access to their client wg. It will first be used to generate a key pair (public and private), responsible for authenticating and allowing the connection between the server and the clients:

WG_PRIV_KEY=$(wg genkey)
WG_PUB_KEY=$(echo $WG_PRIV_KEY | wg pubkey)

echo $WG_PRIV_KEY
echo $WG_PUB_KEY

Since both commands above only print the keys, I put them into a variable to enable the next step, where I persist them into two files to avoid forgetting them:

sudo mkdir /etc/wireguard
echo $WG_PRIV_KEY | sudo tee /etc/wireguard/wg0-private.key
echo $WG_PUB_KEY | sudo tee /etc/wireguard/wg0-public.key

I used the prefix 'wg0' since it will be the name of a newly created network in next steps. With Wireguard, you will be able to create multiple private networks inside a single server.

Configuring the interface

The next step is where you enable IP forwarding on your server. It is needed when a server is acting as a router or Network Address Translation (NAT) and enables the server to forward packets to other destinations.

sudo sysctl -w net.ipv4.ip_forward=1
sudo sysctl -w net.ipv6.conf.all.forwarding=1

Now, it is needed to properly configure your new network, which will be named wg0. You will write a file at /etc/wireguard/wg0.conf, and inside this config, you will need to reference the main interface's name, so the first step is to find it:

ip route show default | awk '/default/ {print $5}'

Keep this result in hand and you will replace it where it is written [NAME] in the following example. Also, keep in hand the value from $WG_PRIV_KEY (the same from /etc/wireguard/wg0-private.key), and you will put it where it is written [PRIVATE_KEY] (remember to remove the brackets too).

sudo nano /etc/wireguard/wg0.conf
[Interface]
PrivateKey = [PRIVATE_KEY]
ListenPort = 51820
SaveConfig = true
Address = 10.5.0.0/29

PostUp = ufw route allow in on wg0 out on [NAME]
PreDown = ufw route delete allow in on wg0 out on [NAME]

PostUp = iptables -t nat -I POSTROUTING -o [NAME] -j MASQUERADE -s 10.5.0.0/29
PreDown = iptables -t nat -D POSTROUTING -o [NAME] -j MASQUERADE -s 10.5.0.0/29

Let's understand what each line means:

  • PrivateKey: is the private key for this node and must never be shared (only the public key will be exchanged to pair nodes);
  • ListenPort: since this Wireguard node is a server, this option specifies the public port for incoming VPN connections and won't exist in the client's config. Every new network needs an exclusive port. It will be opened on the firewall further and must be opened in your cloud's firewall too;
  • Address: this option specifies the subnet range for peers on this network. When set as 10.5.0.0/29, the prefix /29 is the smallest multi-host network and allows having up to 6 client peers, that is: 10.5.0.0 is the network address, 10.5.0.1 the first usable address, 10.5.0.6 the last usable address, and 10.5.0.7 is the broadcast address. You could have other prefixes to allow more client peers. If you don't know about CIDR notation, visit this page: https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing;
  • PostUp and PreDown: can appear multiple times in a config file and are used to run scripts after the network goes up and before it goes down. PreUp and PostDown also exist, but aren't used here. The scripts on it are:
    • allowing traffic coming from wg0 to be routed to your system's main network;
    • tells the iptables to modify packets after the routing is defined and are about to leave the interface (the POSTROUTING option) and MASQUERADE them to make these packets look like they were generated by this network (by replacing the IP address from the private network with the public network's one);

With the server fully configured, it is only necessary to open the ListenPort on the firewall's config and then start the service for the wg0 network:

sudo apt-get install ufw -y
sudo ufw allow 51820/udp
sudo ufw enable
sudo ufw reload
sudo systemctl enable [email protected]
sudo systemctl start [email protected]
sudo systemctl status [email protected]

Configuring your device

With the server up and running, it is needed to set up the client. Everything is very similar to the server's step and won't be replicated here, basically, repeat what is under Configuring the server > Basic setup.

The config is a little bit similar but has some differences. Keep in hand the server's public key (the file /etc/wireguard/wg0-public.key on the server) to replace [SERVER_PUB_KEY], the server's public IP to replace the text [SERVER_PUBLIC_IP], and the client's private key (/etc/wireguard/wg0-private.key on your local machine after running the "Basic setup") to replace [CLIENT_PRIVATE_KEY]. Be careful to avoid mixing which one is the server's and the client's keys. Let's write the file:

sudo nano /etc/wireguard/wg0.conf
[Interface]
PrivateKey = [CLIENT_PRIVATE_KEY]
Address = 10.5.0.1/32

[Peer]
PublicKey = [SERVER_PUB_KEY]
AllowedIPs = 0.0.0.0/0
Endpoint = [SERVER_PUBLIC_IP]:51820

Digging into the options that differ from the server:

  • Address: a specific IP within the range configured on the server that will be assumed by this peer. The /32 means that it is a single address, not a range like while configuring the server. 10.5.0.1 is the first usable address and you can have other clients using up to 10.5.0.6, as explained previously;
  • PublicKey: is the public key from the server. Again, be careful to avoid confusing the keys;
  • AllowedIPs: tells the network which IP addresses traffic should be forwarded through to the VPN (wg0 network). By choosing 0.0.0.0/0, everything will go through it. This option could be different, like if you wanted to proxy traffic only for some websites (but you need to specify the IP, like 1.1.1.1.1, 2.2.2.2.2...);
  • Endpoint: the server's public address and the port.

Finishing the server

The last config is to make the server allow a client to connect to it, by making them "peers". The path is the same made on the client's configuration where the server's public key was provided, but now it is setting up the client's public key on the server.

This instruction uses the command line to avoid editing the file every time a new client appears. Run this on the server:

sudo wg set wg0 peer [CLIENT-PUB-KEY] allowed-ips 10.5.0.1/32

And if you want to see some network information like the peer list and statistics, just run sudo wg.

Finishing the client

Since everything has been configured, the last step is to enable Wireguard on the client, just as you did on the server. However, on the client I prefer to use the wg-quick command instead of starting it as a daemon using systemctl, as on the server (which can also be done on the client).

sudo wg-quick up wg0

To check if everything is correct, do the curl request below from the client and confirm that the IP is the same from the server:

curl -4 ifconfig.me/ip

Going further

If you want to learn more about Wireguard, I recommend going to this (unofficial) https://github.com/pirate/wireguard-docs.

Although this guide showed how to configure Wireguard only for proxying, you can also use it to connect peers on a private network. This is commonly used by companies to restrict access to their internal systems only for those who is inside the company's network and can be used, for example, for accessing a computer at home (with no public address) from anywhere.

πŸ¦† πŸ–€ πŸ’»