Your own private VPN
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