Hometutorials
wireguard mesh vpn

Jump toUpdate content

Setting up a private mesh VPN with WireGuard®

Reviewed on 17 March 2022Published on 02 July 2020
  • mesh-VPN
  • WireGuard
  • multi-site

WireGuard - Overview

WireGuard is a modern VPN (Virtual Private Network) software. It is designed to be run almost anywhere, and to be cross-platform. Compared to other similar software, it is faster, more secure and simpler.

In this tutorial, we show how to use Wireguard to spin up a private mesh network to create a secure private connection between your different servers and Instances. A mesh network allows your devices to communicate between each other using a Virtual Private Network without the need for a central server:

We use two Instances, one located in the PAR-1 region, the other located in the AMS-1 region, and create a virtual network between them.

Tip: If you are looking to configure Wireguard as a VPN to provide secure Internet access, [check out our other Wireguard tutorial](/tutorials/install-wireguard/).
Requirements:

Downloading and installing WireGuard

  1. Log into each of your Instances using SSH:

    ssh root@my.compute.instance.ip
  2. Update and upgrade your system, install the kernel headers for your version and install WireGuard using apt:

    apt update && apt upgrade -y
    apt install linux-headers-$(uname --kernel-release) # installs the right kernel headers for your version
    apt install wireguard
  3. Check that Wireguard is successfuly installed by running: wg. If you get no output, this indicates correct installation. In order to check that the WireGuard kernel module has loaded you can run modprobe wireguard. Depending on your system configuration, a reboot might be required to activate the wireguard module.

  4. Generate the public and private keys for WireGuard:

cd /etc/wireguard
umask 077
wg genkey | tee privatekey | wg pubkey > publickey

Configuring Wireguard manually

Smaller VPNs can be configured using the wg0.conf configuration file of Wireguard. The following parameters are set in the configuration file:

  • 192.168.1.1 is a randomly chosen private IP address for the VPN interface of the virtual Instances located in PAR-1.
  • 192.168.1.2 is a randomly chosen private IP address for the VPN interface of the virtual Instances located in AMS-1.
  • The Endpoint is the public IP address of every other instance.
  • 52345 is a randomly chosen UDP port number used for the communication of the VPN.

On the first Instance

Note:

In this example we assume the Instance is located in the PAR-1 region.

Create the file /etc/wireguard/wg0.conf with the following content. Replace the values in pointy brackets as necessary:

[Interface]
PrivateKey = <PAR-1-instance-private-key>
Address = 192.168.1.1
ListenPort = 52345

[Peer]
PublicKey = <AMS-1-instance-public-key>
AllowedIPs = 192.168.1.2
Endpoint = <AMS-1-instance-public-IP>:52345

On the second Instance:

Note:

In this example we assume the Instance is located in the AMS-1 region.

Create the file /etc/wireguard/wg0.conf with the following content. Replace the values in pointy brackets as necessary:

[Interface]
PrivateKey = <AMS-1-instance-private-key>
Address = 192.168.1.2
ListenPort = 52345

[Peer]
PublicKey = <PAR-1-instance-public-key>
AllowedIPs = 192.168.1.1
Endpoint = <PAR-1-instance-public-IP>:52345

Enabling the Wireguard VPN

  1. Enable and start Wireguard on both Instances using systemctl:

    systemctl enable wg-quick@wg0
    systemctl start wg-quick@wg0
  2. Test the VPN connection on each Instance using the ping command:

    root@PAR-1:~# ping 192.168.1.2
    PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data.
    64 bytes from 192.168.1.2: icmp_seq=1 ttl=64 time=2.87 ms
    64 bytes from 192.168.1.2: icmp_seq=2 ttl=64 time=0.992 ms
    64 bytes from 192.168.1.2: icmp_seq=3 ttl=64 time=1.37 ms
    64 bytes from 192.168.1.2: icmp_seq=4 ttl=64 time=1.21 ms
    64 bytes from 192.168.1.2: icmp_seq=5 ttl=64 time=1.57 ms
    ©64 bytes from 192.168.1.2: icmp_seq=6 ttl=64 time=1.43 ms
    --- 192.168.1.2 ping statistics ---
    6 packets transmitted, 6 received, 0% packet loss, time 5008ms
    rtt min/avg/max/mdev = 0.992/1.577/2.873/0.607 ms
    root@AMS-1:~# ping 192.168.1.1
    PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
    64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=1.72 ms
    64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=1.45 ms
    64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=1.35 ms
    64 bytes from 192.168.1.1: icmp_seq=4 ttl=64 time=1.35 ms
    64 bytes from 192.168.1.1: icmp_seq=5 ttl=64 time=1.25 ms
    64 bytes from 192.168.1.1: icmp_seq=6 ttl=64 time=1.44 ms
    --- 192.168.1.1 ping statistics ---
    6 packets transmitted, 6 received, 0% packet loss, time 5008ms
    rtt min/avg/max/mdev = 1.257/1.429/1.724/0.148 ms

    As you can see, each Instance responds to the ping command of the other peer, indicating that the VPN connection is active.

    Tip:

    If you have problems with the ping, check the content of your wg0.conf files and then use the command systemctl restart wg-quick@wg0

    You can now transfer data between your Instances over a secure private network connection.

Automatizing configuration generation

When managing a large number of machines in a WireGuard mesh network, configuring them manually can be time-consuming. Several projects facilitate the automatized generation of WireGuard configurations to manage your mesh networks with ease. We will use a python script called WireGuard Mesh Configurator to generate the configurations for our Instances.

You can carry out the following steps on your local machine, or any Instance:

  1. Make sure git, python3-pip, and python3 are installed on your machine:

    apt install git python3-pip python3 libncurses-dev -y
  2. Clone the GitHub repository of the configurator script:

    git clone https://github.com/k4yt3x/wg-meshconf
  3. Enter the script’s directory and install the requirements for it:

    cd wg-meshconf
    pip3 install -r requirements.txt
  4. Launch the interactive WCG shell:

    python3 wireguard_mesh_configurator.py int

    Every profile created in the WireGuard Mesh Configurator (WCG) contains a complete network topology. Start by creating a new profile for the mesh network. Once a new profile is created, you will be prompted automatically to enroll new peers.

  5. Type new in the WCG shell to launch the creation of a new profile:

    [WGC]> new
    WireGuard Mesh Configurator 1.2.0
    (C) 2018-2019 K4YT3X
    Licensed under GNU GPL v3
    [WGC]> new
    [!] WARNING: This will flush the currently loaded profile!
  6. Type add to add a new peer and enter the details of the new peer:

    [WGC]> add
    [?] USER: Address (leave empty if client only) [IP/CIDR]: 10.1.0.1/16
    [?] USER: Public address (leave empty if client only) [IP|FQDN]: 1.1.1.1
    [?] USER: Listen port (leave empty for client) [1-65535]: 7000
    [?] USER: Private key (leave empty for auto generation):
    [?] USER: Keep alive? [y/N]:

    [?] USER: Alias (optional):
    [?] USER: Description (optional):
    [+] INFO: 10.1.0.1/16 information summary:
    Address: 10.1.0.1/16
    Public Address: 1.1.1.1
    Listen Port: 7000
    Private Key: 2JgqbhrtAiN1yZ5C3tjvlRwFWOrXflb3pKKhW/DJ3EI=

    Repeat these step for all peers in the mesh network.

  7. Export everything into Wireguard configuration files, using the following command to generate the configuration files and dump them in the /tmp/wg-conf directory:

    [WGC]> gen /tmp/wg-conf
    [WGC]> gen /tmp/wg-conf
    [+] INFO: Generating configuration files
    [?] USER: Output directory doesn't exist. Create output directory? [Y/n]:

    2020-07-27 14:51:29.787508 [+] INFO: Generating configuration file for 10.1.0.1/16
    gNNBi1eYUj5Wa6Qh21VvpEQhB9CFt4y6breHLhk49lo=
    mFWz1E/ZLdavy8dz9pKPx58x7UBTwHpd61ZLxDjjFFU=
    AEJ42t6rT/FxBq5MF1klzTZZrexh5qXvDUnnAU1njnY=
    2020-07-27 14:51:29.802540 [+] INFO: Generating configuration file for 10.2.0.1/16
    2JgqbhrtAiN1yZ5C3tjvlRwFWOrXflb3pKKhW/DJ3EI=
    mFWz1E/ZLdavy8dz9pKPx58x7UBTwHpd61ZLxDjjFFU=
    AEJ42t6rT/FxBq5MF1klzTZZrexh5qXvDUnnAU1njnY=
    2020-07-27 14:51:29.817690 [+] INFO: Generating configuration file for 10.3.0.1/16
    2JgqbhrtAiN1yZ5C3tjvlRwFWOrXflb3pKKhW/DJ3EI=
    gNNBi1eYUj5Wa6Qh21VvpEQhB9CFt4y6breHLhk49lo=
    AEJ42t6rT/FxBq5MF1klzTZZrexh5qXvDUnnAU1njnY=
    2020-07-27 14:51:29.832823 [+] INFO: Generating configuration file for 10.4.0.1/16
    2JgqbhrtAiN1yZ5C3tjvlRwFWOrXflb3pKKhW/DJ3EI=
    gNNBi1eYUj5Wa6Qh21VvpEQhB9CFt4y6breHLhk49lo=
    mFWz1E/ZLdavy8dz9pKPx58x7UBTwHpd61ZLxDjjFFU=

    Then exit WGC:

    [WGC]> exit
    [!] WARNING: Exiting
  8. Copy the created Wireguard configuration files to each Instance using any method you like (SFTP, FTPS, plain copy & paste, etc.). Make sure to store the configuration at /etc/wireguard/wg0.conf to be able to use the wg-quick command for express configuration.

  9. SSH into each of the Instance peers and configure WireGuard. We use the wg-quick command to create an interface using our generated configuration and make it a service, so the interface will be configured aSticksutomatically duing system boot. Repeat these step on any of the peers.

    wg-quick up wg0
    systemctl enable wg-quick@wg0

You have now successfully configured a mesh network using WireGuard which allows your Instances to communicate between themselves via a private and encrypted connection. As there is no central server, the network will continue to work if one of the peers fails.

For more information about WireGuard, refer to the official documentation.

“WireGuard” is a registered trademark of Jason A. Donenfeld.