VPNs are very practical tools that allow you to secure the connection between two machines, to secure your connection to the Internet when you connect in public places or to bypass geographical access restrictions. When you have a personal server and you don’t want to expose it to the public, a VPN is ideal to reduce the attack surface and access your tools.
For a long time, I used OpenVPN, which was quite heavy to configure and set up, and not always easy to maintain… until the arrival of Wireguard.
Wireguard is a more recent tool, completely open source, very light, simple to set up, which claims to comply with the latest encryption standards and is particularly efficient. It has recently been integrated into the Linux kernel and has clients for Windows, Mac, iOS or Android.
For this example, we will connect a “server” with a “client”. In reality, all the devices connected through Wireguard are perfectly equivalent, and it is possible to configure the data transfers as you wish.
Installation
Under Arch Linux, Wireguard is already integrated in the Linux kernel, but installing wireguard-tools
allows to get simple configuration tools.
Keys creation
To communicate, each device will need a public key and an associated private key. The public key must be shared with each machine with which we wish to communicate, and we must benefit in return from their public keys.
Thus, for this example, we will create a private key wg.key
with the right permissions, and the corresponding public key wg.pub
:
cd .ssh
(umask 0077; wg genkey > server.key)
wg pubkey < server.key > server.pub
We do the same by creating a set of keys for the client:
cd .ssh
(umask 0077; wg genkey > client.key)
wg pubkey < client.key > client.pub
Finally, although it is not mandatory, you can create pre-shared keys that will be used on both devices to strengthen security:
(umask 0077; wg genpsk > preshared.pub)
Server configuration
The configuration is done in the /etc/wireguard/wg0.conf
file where we will start by declaring our interface. Specify the contents of the private key server.key
in PrivateKey
and the port in ListenPort
. The PostUp
and PostDown
lines designate the commands to be run when activating or deactivating the Wireguard network respectively. These indicate that we have to reroute everything that is requested from or to our client. Your server will have the address 10.0.0.1
on the Wireguard network.
[Interface]
PrivateKey = ...
Address = 10.0.0.1/24
ListenPort = 51871
PostUp = sysctl -w net.ipv4.ip_forward=1; 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
The next step is to specify which clients can connect to the VPN. For each of them, we add in the same file a peer section. Specify the contents of the client’s public key client.pub
in PublicKey
, and always the pre-shared key in PreSharedKey
. Your client will have the address 10.0.0.2
on the Wireguard network.
[Peer]
PublicKey = ...
PreSharedKey = ...
AllowedIPs = 10.0.0.2/32
Client configuration
On the client side, the configuration will also written in /etc/wireguard/wg0.conf
. This time we give it the address 10.0.0.2
and we indicate the private key contained in client.key
:
[Interface]
PrivateKey = ...
Address = 10.0.0.2/24
It is also given the server as peer, the server’s public key contained in server.pub
, and the pre-shared key. The EndPoint
field must indicate the domain name or external IP where the server will be reachable, as well as the port (which must, of course, be externally accessible and routed if necessary). The PersistentKeepalive
field is not mandatory but allows to solve connectivity problems when connecting through a NAT router.
[Peer]
PublicKey = ...
PreSharedKey = ...
AllowedIPs = 0.0.0.0/0
Endpoint = vpn.domain.tld:51871
PersistentKeepalive = 25
The AllowedIPs
field indicates which IPs will be passed through the VPN. With 0.0.0.0/0
, all client IPs will be passed through the VPN. If you want to limit the use of the VPN to local services on the server (e.g. self-hosted apps), you can use 10.0.0.0/24
for example.
To start the VPN, you can run wg-quick up wg0
with root rights, both on the client and on the server. To turn it off, a simple wg-quick down wg0
is enough. It is also possible to use a service to start the VPN automatically at startup:
sudo systemctl enable --now wg-quick@wg0
On a macos client
With Homebrew, we install wireguard tools:
brew install wireguard-tools
We create the folder that will contain the configuration:
sudo mkdir -p /usr/local/etc/wireguard
We then edit /usr/local/etc/wireguard/wg0.conf
:
[Interface]
PrivateKey =
Address = 10.0.0.2/24
DNS = 1.1.1.1
[Peer]
PublicKey = ...
PreSharedKey = ...
AllowedIPs = 0.0.0.0/0
Endpoint = vpn.domain.tld:51871
We can then launch Wireguard with:
sudo wg-quick up
Wireguard on your phone
Wireguard has the advantage of being easily available on both iOS and Android, allowing you to access your local network and applications from any wifi network or with cellular data.
In both cases, the application allows you to enter all the fields in the same way as wg0.conf
, but of course, entering the certificates by hand would be very tedious.
Fortunately, it is also possible to proceed with a QR code!
Create a public key and a shared key for your phone, as described above, as well as a pre-shared key if necessary:
[Interface]
PrivateKey =
Address = 10.0.0.x/24
DNS = 1.1.1.1
[Peer]
PublicKey =
AllowedIPs = 0.0.0.0/0
Endpoint = vpn.domain.tld:51820
Declare them as a peer on your server, and create a wg0-phone.conf
file on your computer.
Once this is done, we can then use qrencode
to transform this configuration file into a QR code directly readable (and importable) by the phone, which will be displayed in the terminal:
qrencode -t ansiutf8 < wg0-iphone.conf
█████████████████████████████████████████████████████
█████████████████████████████████████████████████████
████ ▄▄▄▄▄ █ ▄██▄▄▄ ▀▄ ▄▄█ ▄ █▀▄▄ ▀▀█▀▄█ ▄▄▄▄▄ ████
████ █ █ █ █▀ █▀▀▀▀▀▄█ █ ▄ █▀▄▀▀██ ▀█ █ █ ████
████ █▄▄▄█ █▀ ▄██ ▀▄▀▀ ▀ ▄▄▄ ▀ ▀▀█▀█▄█▄▄▄█ █▄▄▄█ ████
████▄▄▄▄▄▄▄█▄▀ █▄▀▄█▄█ █ █▄█ ▀▄▀▄█▄▀ █ █▄█▄▄▄▄▄▄▄████
████ █▀▄ ▄▀█ █▀▄ ▄███▄▄ ▄▄▀ █▄ ▀ █▀▀▀▀ █▄ ▄▄████
████ ▄▄▄█▄▄▄█▄█ ▄█ ▀ █▄█ ▄██▀▀ █ ▄▀▄ ▄██▀▀▀██▄▀████
████▄█▀ ▀▄▀ █▄▄▀▄███▄▄▄▀ ██▄▀█▀█▀ ▀█▄█ ▀ █▄▀ ▀█████
████▀▄▄█▀█▄ █▀ ▀▄ █▀██ ▄█▀█ ▀ ██ ▄▄▄█ █▀▄█▀ ████
████ ▀▀█▀█▄▀ █▄ ▀▀▀▀█ ▄█▀ █▀▄ █ ▀▀ ▄ ▀▄▀ ███▀▄████
█████▀█▄▄▀▄▄▀ ▀ ▄▄█▀▄▀▀ ▄ ▀▀ █ ▄█▄▀▀█▄▀▀▄ █ █████
████ █▀▀ ▄▄▄ ▄▄▄█ ▀█▄▄▄ ▄▄▄ ▀ █ ▄█ ▀█ ▄▄▄ ▀▀ ▀████
████▄ █ █▄█ ▀ ▀█▀ ▀▀ █▄█ █▄ ▄█▀▄ █▄█ ████████
██████ █▄ ▄ █▄▀▄▄ ▄█▄ ▄ ▄ ▄▀█▄▀█ ██▄ ▄▄ █▀ ████
████ ██▄▄█▄▄▄▀█▄ ▄▄▀ ▄▄▀█▀█▄█ ▀▄▄ ███▀▄▀██▄▄▀▀ ▀████
██████ ▄ ▄█▄ ▄▀▀ ▄█ ▄▄█ ██▄ ▄▀▀ ▄ ▄█▄▀▄ ▀▄█ █████
████ ▄▄ █▀▄▄▄▀ ▀▀▄ █▀▀▀█ ▀█▄▀▀ █ ▄▄█ ▄▄█ ▀▀▀▄▄▀▀████
████ ▀█ ▄██▀█▄ ▀▀▀▀██▀▄▄█ ▄ ▄▄▀█ ▀▄▄█ █▀█▀ ▀██▀████
█████▀▀▀ █▄▄▀ ▀▀█▄ ▄█▀▄█▄▀▀▄█▀▀▀ █ █ ▄▀▄ ▄▀▄█▀▀▄▀████
████▄██▄▄█▄▄▀ ██▄▀ ████ ▄▄▄ ███ ▄█▀ ▀▀ ▄▄▄ ▀ ▄████
████ ▄▄▄▄▄ █▀██▄▀▀█▄ ▄██ █▄█ █▀▀▄▄▀▄█ █▄█ ▄▄█▄████
████ █ █ █▄█ ▀▄▄ ██▄ █ ▄▄ ██▄█▄ ▄ ██▄ ▄ ▀█▀█████
████ █▄▄▄█ █▀▄ ▄ ▄▄ █ ▄ █ ▀▀ ▄ ▄▄█▀ █▀▄█ █▀██████
████▄▄▄▄▄▄▄█▄▄▄██▄██▄█▄▄█▄▄██▄▄█▄██▄▄█▄▄▄▄██████▄████
█████████████████████████████████████████████████████
█████████████████████████████████████████████████████