Setting up Wireguard
Set up your own VPN on your own server, in just about half an hour. This post describes the process of setting up a WireGuard VPN and client.
Yesterday, I set up a Wireguard VPN. I did find some scripts to automate the process, but since I like fine grained control over my system and would not like to install more packages or files than required, I decided to do things manually. Here's a quick summary of what I did, so you can follow suit.
First things first
If you know what you're doing, you can skip this part.
What we're going to do requires a server. You can get a server in many ways - there exist tons of VPS providers, for example Digital Ocean, Amazon AWS, Google Cloud, Hetzner, and so on. Pick one you like, and buy a server. You don't need a powerful server since Wireguard isn't exactly resource intensive, so whatever the cheapest plan is should do just fine.
The way this works is that all the traffic from your computer will be routed through the server and then reach its destination, and all the traffic back to your computer will first go through the server. This means that all the data exchange between the target server and your machine goes through your server - It's as if you were physically where your server is and browsing the internet through a monitor connected to your server.
This can be helpful in case your ISP has shady privacy policies, or if they block totally innocent websites like Telegram, DigitalOcean, or DuckDuckGo (yes, this actually happened to someone I know) and you want to get around it.
Installing Wireguard
You first need to install Wireguard on both the server and the client. If you're on Ubuntu, this is a simple process:
$ sudo apt install wireguard
If you're using Debian Bullseye, the command above works, since it's in the official repos. However, if you're using Debian Buster or below, you'll need to enable the backports repo this way:
$ sudo sh -c "echo 'deb http://deb.debian.org/debian buster-backports main' > /etc/apt/sources.list.d/buster-backports.list"
$ sudo apt update
and then install it using:
$ sudo apt install wireguard
In case the client machine is not using Linux, you can find Wireguard for Windows and macOS here. On most other Linux distros, you should be able to just install the wireguard
package. If that doesn't apply for you or you have other questions, have a look at the official installation instructions.
Generating Keys
These keys are used for encryption and decryption of data. We'll need to generate a private and public key on both the server and the client machine, so let's do it now.
Note that if you get Permission denied
while trying to cd into /etc/wireguard
, that's because you need root permissions, you can become root using sudo -s
.
# cd /etc/wireguard
# wg genkey | tee privatekey | wg pubkey > publickey
# chmod 600 privatekey publickey
The commands are simple - we first go to /etc/wireguard
, use the wg genkey
command to generate a private key, pipe the private key to wg pubkey
to generate a public key, and then set their permissions to 600
. This means that we can read or write to the file, but no other user except the superuser can. Make sure to run these commands on both the server and the client machine.
Once that's done, you now have two sets of keys - a public and private key on the server and a public and private key on the client.
Now, you need to find your network interface name, which you can do using:
$ ip route list default | awk '{print $5}'
Let's refer to
-
Server Public Key as
SRV_PUB
-
Server Private Key as
SRV_PRIV
-
Client Public Key as
CLT_PUB
-
Client Private Key as
CLT_PRIV
-
Network Interface Name as
NET_INTF
from now on.
Creating the config file
On the server
Create the file /etc/wireguard/wg0.conf
, and insert the following into it:
[Interface]
Address = 192.168.10.1/24
SaveConfig = true
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o <NET_INTF> -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o <NET_INTF> -j MASQUERADE; iptables -A FORWARD -o wg0 -j ACCEPT
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o <NET_INTF> -j MASQUERADE; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -D POSTROUTING -o <NET_INTF> -j MASQUERADE; iptables -D FORWARD -o wg0 -j ACCEPT
ListenPort = 51820
PrivateKey = <SRV_PRIV>
[Peer]
PublicKey = <CLT_PUB>
AllowedIPs = 192.168.10.2/32
Replace <SRV_PRIV>
and <CLT_PUB>
with the server private key and the client public key respectively.
On the client
Create the file /etc/wireguard/wg0.conf
, and insert the following into it:
[Interface]
PrivateKey = <CLT_PRIV>
Address = 192.168.10.2/24
[Peer]
PublicKey = <SRV_PUB>
AllowedIPs = 0.0.0.0/0
AllowedIPs = ::0/0
Endpoint = <SRV_IP>:51820
PersistentKeepalive = 25
Replace <CLT_PRIV>
, <SRV_PUB>
, and <NET_INTF>
with the client private key, the server public key, and the network interface name respectively.
Replace <SRV_IP>
with the public IP address of the server. If you don't know what this is, you can execute $ curl icanhazip.com
on the server to get it.
Finishing up
Setting up UFW rule
First, you need to check if ufw is installed by running:
$ which ufw
If it says ufw not found
, you don't need to do anything.
If not, you need to tell UFW to allow udp traffic to pass through the port 51820. To do this, execute:
$ sudo ufw allow 51820/udp
Firing it up
Server
To start Wireguard on the server, execute:
$ sudo systemctl start wg-quick@wg0
Verify that starting the service was successful using:
$ systemctl status wg-quick@wg0
the output should be something like:
● [email protected] - WireGuard via wg-quick(8) for wg0
Loaded: loaded (/lib/systemd/system/[email protected]; enabled; vendor preset: enabled)
Active: active (exited) since Tue 2021-03-02 00:16:28 CET; 15h ago
.....
Process: 30685 ExecStart=/usr/bin/wg-quick up wg0 (code=exited, status=0/SUCCESS)
In case you use a different init system, you can run sudo wg-quick up wg0
.
Client
To start Wireguard on the client, execute:
$ sudo wg-quick up wg0
Verify that you're connected to the VPN by executing:
$ sudo wg
The output should be something like:
interface: wg0
public key: <CLT_PUB>
private key: (hidden)
listening port: 38520
peer: <SRV_PUB>
endpoint: <SRV_IP>:51820
allowed ips: 0.0.0.0/0
latest handshake: 15 seconds ago
transfer: 3.58 MiB received, 761.63 KiB sent
persistent keepalive: every 25 seconds
Verify that you can access the internet by executing:
curl icanhazip.com
-- the output should be the same as the external IP of your server.
If you can't access the internet but ping <SRV_IP>
works while connected with Wireguard, you might need to add the following lines to /etc/sysctl.conf
:
net.ipv6.conf.all.forwarding = 1
net.ipv4.ip_forward = 1
Now, to load the values, run $ sudo sysctl -p
Hopefully, everything should be working perfectly now. Have fun! :)