---
title: Setting up a private mesh VPN with WireGuard®
description: Learn to configure a secure, private mesh VPN using WireGuard®. Ideal for connecting multiple servers in a network without a central server.
tags: mesh-VPN WireGuard multi-site
hero: assets/scaleway_wireguard.webp
products:
  - instances
dates:
  validation: 2025-07-28
  posted: 2020-07-02
  validation_frequency: 12
difficulty: beginner
usecase:
  - deploy-external-software
ecosystem:
  - third-party
---
import image from './assets/scaleway-wireguard_mesh.webp'

import Requirements from '@macros/iam/requirements.mdx'


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

In this tutorial, we show you 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 with each other using a Virtual Private Network without the need for a central server:

<Lightbox image={image} alt="" />

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

<Message type="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/).
- We recommend you follow this tutorial using a [Learning Instance](/instances/reference-content/choosing-instance-type/).
</Message>

<Requirements />

- A Scaleway account logged into the [console](https://console.scaleway.com)
- [Owner](/iam/concepts/#owner) status or [IAM permissions](/iam/concepts/#permission) allowing you to perform actions in the intended Organization
- An [SSH key](/organizations-and-projects/how-to/create-ssh-key/)
- 2 [Instances](/instances/how-to/create-an-instance/) running a Linux kernel ≥ 3.10

## 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. Run `wg` to make sure WireGuard is installed. You should get no output, indicating that WireGuard was correctly installed. You can run `modprobe wireguard` to check that the WireGuard kernel module has loaded. 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
    ```

5. Run `cat privatekey` and `cat publickey` for both Instances to retrieve their private and public keys. An output similar to the following displays:

```
root@scw-instance-ams1:/etc/wireguard#  cat privatekey
uJHRlma4LK8maULzMHWATJtGLs9yPvv+/+Rqj8UKU3k=
root@scw-instance-ams1:/etc/wireguard# cat publickey
ioytQhwtItPx0mnAyCRBaarxL5x5a3q5dUg2mthdlTw=
```

## 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

<Message type="note">
  In this example, we assume that the Instance is the one we created in the `PAR-1` region.
</Message>

Create the directory in which you will save your file using the following command `mkdir -p /etc/wireguard`.

Create the file `/etc/wireguard/wg0.conf` using the following command: `nano /etc/wireguard/wg0.conf` and paste the following content. Replace the values in the 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
```
Your file should look like the following:

```
[Interface]
PrivateKey = IMR/CZzu5hVJNPqWXhj+H4cHUbCPlvn91VwN3jVNOGw=
Address = 192.168.1.2
ListenPort = 52345

[Peer]
PublicKey = vIsJ+ZXVc8t8mkkpUIaqHKu9hE8PERT0lxb5nowDkx8=
AllowedIPs = 192.168.1.1
Endpoint = 163.172.141.6:52345
```
### On the second Instance:

<Message type="note">
  In this example, we assume that the Instance is the one we created in the `AMS-1` region.
</Message>

Create the directory in which you will save your file using the following command `mkdir -p /etc/wireguard`.

Create the file `/etc/wireguard/wg0.conf` using the following command: `nano /etc/wireguard/wg0.conf` and paste the following content. Replace the values in the 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.service
    systemctl start wg-quick@wg0.service
    ```
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.

    <Message type="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`.
    </Message>

    <Message type="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.service`.
    </Message>

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

## Automating 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 automated generation of WireGuard configurations to manage your mesh networks with ease. We will use a Python script called [WireGuard Mesh Configurator](https://github.com/k4yt3x/wg-meshconf) 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 script you need for the configuration:
    ```
    git clone https://github.com/k4yt3x/wg-meshconf
    ```
3. Enter the script's directory and install the requirements for it:
    ```
    cd wg-meshconf
    pip install 'wg-meshconf@git+https://github.com/k4yt3x/wg-meshconf.git'
    ```
4. Create a new configuration:
    ```
    wg-meshconf init
    ```
5. Type `wg-meshconf addpeer <PEERNAME> --address=<SUBNET>` to create a new peer. Make sure you replace the information between brackets as necessary.

    ```
    wg-meshconf addpeer peer1 --address=192.168.19.21/24
    `````
   Repeat this step for all peers in the mesh network.

6. Run `wg-meshconf showpeers` to make sure your peers have been added correctly.

    ```
    ┏━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
    ┃ Name  ┃ Address          ┃ ListenPort ┃ PrivateKey                           ┃
    ├───────┼──────────────────┼────────────┼──────────────────────────────────────┤
    │ peer1 │ 192.168.19.21/24 │ 51820      │ cLtiGRp0mGzVwnKVf9skY9mxYv78EtPA0x4… │
    ├───────┼──────────────────┼────────────┼──────────────────────────────────────┤
    │ peer2 │ 192.168.2.0/24   │ 51820      │ 4EzxxPIadfpQzIFE0dyPqLGoZrm49iHy04X… │
    └───────┴──────────────────┴────────────┴──────────────────────────────────────┘
    ```

7. Use the following command to generate the configuration files for all peers `wg-meshconf genconfig`. The configuration files will be named after the peers' names. By default, all configuration files are exported into a subdirectory named `output`.
8. Access a specific configuration file using the following commands:

    ```
    cd output
    cat user1.conf
    ```

9. 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.
10. 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 automatically during system boot. Repeat this step on any of the peers.
    ```
    wg-quick up wg0
    systemctl enable wg-quick@wg0.service
    ```

You have now 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](https://www.wireguard.com/quickstart/).

“WireGuard” is a registered trademark of [Jason A. Donenfeld](https://www.zx2c4.com/).
<ClickableBanner
  productLogo="generic"
  title="Easily set up a secure and scalable VPN network with WireGuard on Scaleway."
  url="https://account.scaleway.com/register"
  label="Create your account"
/>