Ramón Calvo's picture
Ramón Calvo
Robotics Engineer

Your own private VPN

Published on 12 Jun 2023

In the past, I often used to remotely connect to my desktop computer at home to perform intensive tasks such as compiling programs or doing ML workloads. To achieve this, I simply opened the router port and had a free reverse DNS service that would automatically bind my home’s current IP to a domain name. It was a simple solution and it worked quite well.

Today, while working on my master thesis, I find myself in a slightly more complex scenario: I have my computer at home, as well as a workstation behind a university firewall, and I want to be able to work from my laptop when necessary or connect either workstation with one another. I thought of leveraging my VPS by hosting a VPN server there.

I decided to give Wireguard a try, since it is a recent, lightweight and performant VPN implementation that works on multiple platforms and it is included by default in recent Linux kernel versions. Moreover, the set-up was straight forward and the config files turned out to be very short.

I’ll share my setup since I think that it might be useful for other people. But please bear in mind that I am not a network engineer so I don’t really know if this is the best way of doing things.

The first step would be to install wireguard-tools on your server and clients. For MacOS, I’d recommend installing wireguard to brew, since the AppStore client app gave me some problems when I tried to SSH into the other computers.

I don’t want to pass all my network traffic through the VPN, but rather just to create a subnet so that I can connect all my computers and devices together. This way, each device will have its own gateway to the internet untouched.

You will have to generate a pair of private and public keys for the server and all the clients that will be connected to the VPN. To generate a pair, you can run:

wg genkey | tee privatekey | wg pubkey > publickey

On your server, open the file /etc/wireguard/wg0.conf and write:

[Interface]

Address = 10.0.0.1/24

ListenPort = 41194

PrivateKey = <your_server_privatekey>

# You will need to add this for every device you would like to add
# to your network
[Peer]
Publickey = <your_client_publickey>

# This is the IP that will be assigned to this client
AllowedIPs = 10.0.0.2/32

I chose to create a local net with the prefix 10.0.x.x so that it does not collide with each computer’s home subnet 192.168.x.x. You can in fact check that this is what happens when I define the adresses and masks.

On every client, install wireguard and write the following in /etc/wireguard/wg0.conf:

[Interface]

PrivateKey = <your_client_privatekey>

# The IP you assigned to your client
AllowedIPs = 10.0.0.2/24

[Peer]

PublicKey = <your_server_publickey>

# We want this client to be able to access every other device in the subnet
AllowedIPs = 10.0.0.0/24

Endpoint = <your_domain_or_server_ip>:41194

# Keeps the connection alive
PersistentKeepalive = 15

Then, on the server and every client, enable and activate Wireguard:

sudo systemctl start wg-quick@wg0
sudo systemctl enable wg-quick@wg0

And that’s all! If you followed this configuration you now should be able to connect between your computers too.

Note: I had some problems with SSH that I solved by putting the following under the [Interface] section of my server config:

PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat
    -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -A FORWARD
    -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o eth0
    -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t
    nat -D POSTROUTING -o eth0 -j MASQUERADE; ip6tables
    -D FORWARD -i wg0 -j ACCEPT; ip6tables -t nat
    -D POSTROUTING -o eth0 -j MASQUERADE