Prometheus WireGuard Exporter

legal stability-stable

Crate cratedown cratelastdown

release tag

Rust build commitssince

Docker build

dockeri.co

Intro

A Prometheus exporter for WireGuard, written in Rust. This tool exports the wg show all dump (or wg show <interface> dump if you specify a config file) results in a format that Prometheus can understand. The exporter is very light on your server resources, both in terms of memory and CPU usage.

Changelog

Prerequisites

Alternatively, as long as you have Wireguard on your host kernel with some Wireguard interfaces running, you can use Docker. For example:

```sh docker run -it --rm --init --net=host --cap-add=NET_ADMIN mindflavor/prometheus-wireguard-exporter

Check it's up

docker run -it --rm alpine:3.12 wget -qO- http://localhost:9586/metrics ```

Compilation

To compile the latest master version:

bash git clone https://github.com/MindFlavor/prometheus_wireguard_exporter.git cd prometheus_wireguard_exporter cargo install --path .

If you want the latest release you can simply use:

bash cargo install prometheus_wireguard_exporter

You can also build the Docker image with

sh docker build -t mindflavor/prometheus-wireguard-exporter .

Usage

Start the binary with -h to get the complete syntax. The parameters are:

| Parameter | Mandatory | Valid values | Default | Accepts multiple occurrences? | Description | | -- | -- | -- | -- | -- | -- | | -v | no | | | No | Enable verbose mode. | -a | no | | | No | Prepends sudo to wg commands. | -l | no | any valid ip address | 0.0.0.0 | No | Specify the service address. This is the address your Prometheus instance should point to. | -p | no | any valid port number | 9586 | No | Specify the service port. This is the port your Prometheus instance should point to. | -n | no | path to the wireguard configuration file | | No | This flag adds the friendly_name attribute to the exported entries. See Friendly names for more details. | -s | no | | off | No | Enable the allowed ip + subnet split mode for the labels. | -r | no | | off | No | Exports peer's remote ip and port as labels (if available). | -i | no | your interface name(s) | all | Yes | Specifies the interface(s) passed to the wg show <interface> dump parameter. Multiple parameters are allowed.

Once started, the tool will listen on the specified port (or the default one, 9586, if not specified) and return a Prometheus valid response at the url /metrics. So to check if the tool is working properly simply browse the http://localhost:9586/metrics (or whichever port you choose).

Friendly Names

Starting from version 1.2 you can instruct the exporter to append a friendly name to the exported entries. This can make the output more understandable than using the public keys. For example this is the standard output:

```

HELP wireguardsentbytes_total Bytes sent to the peer

TYPE wireguardsentbytes_total counter

wireguardsentbytestotal{interface="wg0",publickey="2S7mA0vEMethCNQrJpJKE81/JmhgtB+tHHLYQhgM6kk=",allowedips="10.70.0.2/32,10.70.0.66/32"} 3208804 wireguardsentbytestotal{interface="wg0",publickey="qnoxQoQI8KKMupLnSSureORV0wMmH7JryZNsmGVISzU=",allowedips="10.70.0.3/32"} 0 wireguardsentbytestotal{interface="wg0",publickey="L2UoJZN7RmEKsMmqaJgKG0m1S2Zs2wd2ptAf+kb3008=",allowedips="10.70.0.4/32"} 0 wireguardsentbytestotal{interface="wg0",publickey="MdVOIPKt9K2MPj/sO2NlWQbOnFJ6L/qX80mmhQwsUlA=",allowedips="10.70.0.50/32"} 0 wireguardsentbytestotal{interface="wg0",publickey="lqYcojJMsIZXMUw1heAFbQHBoKjCEaeo7M1WXDh/KWc=",allowedips="10.70.0.40/32"} 0 wireguardsentbytestotal{interface="wg0",publickey="928vO9Lf4+Mo84cWu4k1oRyzf0AR7FTGoPKHGoTMSHk=",allowedips="10.70.0.80/32"} 0 wireguardsentbytestotal{interface="wg0",publickey="wTjv6hS6fKfNK+SzOLo7O6BQjEb6AD1TN9GjwZ08IwA=",allowed_ips="10.70.0.5/32"} 0

HELP wireguardreceivedbytes_total Bytes received from the peer

TYPE wireguardreceivedbytes_total counter

wireguardreceivedbytestotal{interface="wg0",publickey="2S7mA0vEMethCNQrJpJKE81/JmhgtB+tHHLYQhgM6kk=",allowedips="10.70.0.2/32,10.70.0.66/32"} 71420072 wireguardreceivedbytestotal{interface="wg0",publickey="qnoxQoQI8KKMupLnSSureORV0wMmH7JryZNsmGVISzU=",allowedips="10.70.0.3/32"} 0 wireguardreceivedbytestotal{interface="wg0",publickey="L2UoJZN7RmEKsMmqaJgKG0m1S2Zs2wd2ptAf+kb3008=",allowedips="10.70.0.4/32"} 0 wireguardreceivedbytestotal{interface="wg0",publickey="MdVOIPKt9K2MPj/sO2NlWQbOnFJ6L/qX80mmhQwsUlA=",allowedips="10.70.0.50/32"} 0 wireguardreceivedbytestotal{interface="wg0",publickey="lqYcojJMsIZXMUw1heAFbQHBoKjCEaeo7M1WXDh/KWc=",allowedips="10.70.0.40/32"} 0 wireguardreceivedbytestotal{interface="wg0",publickey="928vO9Lf4+Mo84cWu4k1oRyzf0AR7FTGoPKHGoTMSHk=",allowedips="10.70.0.80/32"} 0 wireguardreceivedbytestotal{interface="wg0",publickey="wTjv6hS6fKfNK+SzOLo7O6BQjEb6AD1TN9GjwZ08IwA=",allowed_ips="10.70.0.5/32"} 0

HELP wireguardlatesthandshake_seconds Seconds from the last handshake

TYPE wireguardlatesthandshake_seconds gauge

wireguardlatesthandshakeseconds{interface="wg0",publickey="2S7mA0vEMethCNQrJpJKE81/JmhgtB+tHHLYQhgM6kk=",allowedips="10.70.0.2/32,10.70.0.66/32"} 1562834127 wireguardlatesthandshakeseconds{interface="wg0",publickey="qnoxQoQI8KKMupLnSSureORV0wMmH7JryZNsmGVISzU=",allowedips="10.70.0.3/32"} 0 wireguardlatesthandshakeseconds{interface="wg0",publickey="L2UoJZN7RmEKsMmqaJgKG0m1S2Zs2wd2ptAf+kb3008=",allowedips="10.70.0.4/32"} 0 wireguardlatesthandshakeseconds{interface="wg0",publickey="MdVOIPKt9K2MPj/sO2NlWQbOnFJ6L/qX80mmhQwsUlA=",allowedips="10.70.0.50/32"} 0 wireguardlatesthandshakeseconds{interface="wg0",publickey="lqYcojJMsIZXMUw1heAFbQHBoKjCEaeo7M1WXDh/KWc=",allowedips="10.70.0.40/32"} 0 wireguardlatesthandshakeseconds{interface="wg0",publickey="928vO9Lf4+Mo84cWu4k1oRyzf0AR7FTGoPKHGoTMSHk=",allowedips="10.70.0.80/32"} 0 wireguardlatesthandshakeseconds{interface="wg0",publickey="wTjv6hS6fKfNK+SzOLo7O6BQjEb6AD1TN9GjwZ08IwA=",allowed_ips="10.70.0.5/32"} 0 ```

And this is the one augmented with friendly names:

```

HELP wireguardsentbytes_total Bytes sent to the peer

TYPE wireguardsentbytes_total counter

wireguardsentbytestotal{interface="wg0",publickey="2S7mA0vEMethCNQrJpJKE81/JmhgtB+tHHLYQhgM6kk=",allowedips="10.70.0.2/32,10.70.0.66/32",friendlyname="OnePlus 6T"} 3208804 wireguardsentbytestotal{interface="wg0",publickey="qnoxQoQI8KKMupLnSSureORV0wMmH7JryZNsmGVISzU=",allowedips="10.70.0.3/32",friendlyname="varch.local (laptop)"} 0 wireguardsentbytestotal{interface="wg0",publickey="L2UoJZN7RmEKsMmqaJgKG0m1S2Zs2wd2ptAf+kb3008=",allowedips="10.70.0.4/32",friendlyname="cantarch"} 0 wireguardsentbytestotal{interface="wg0",publickey="MdVOIPKt9K2MPj/sO2NlWQbOnFJ6L/qX80mmhQwsUlA=",allowedips="10.70.0.50/32",friendlyname="frcognoarch"} 0 wireguardsentbytestotal{interface="wg0",publickey="lqYcojJMsIZXMUw1heAFbQHBoKjCEaeo7M1WXDh/KWc=",allowedips="10.70.0.40/32",friendlyname="frcognowin10"} 0 wireguardsentbytestotal{interface="wg0",publickey="928vO9Lf4+Mo84cWu4k1oRyzf0AR7FTGoPKHGoTMSHk=",allowedips="10.70.0.80/32",friendlyname="OnePlus 5T"} 0 wireguardsentbytestotal{interface="wg0",publickey="wTjv6hS6fKfNK+SzOLo7O6BQjEb6AD1TN9GjwZ08IwA=",allowedips="10.70.0.5/32",friendlyname="folioarch"} 0

HELP wireguardreceivedbytes_total Bytes received from the peer

TYPE wireguardreceivedbytes_total counter

wireguardreceivedbytestotal{interface="wg0",publickey="2S7mA0vEMethCNQrJpJKE81/JmhgtB+tHHLYQhgM6kk=",allowedips="10.70.0.2/32,10.70.0.66/32",friendlyname="OnePlus 6T"} 71420072 wireguardreceivedbytestotal{interface="wg0",publickey="qnoxQoQI8KKMupLnSSureORV0wMmH7JryZNsmGVISzU=",allowedips="10.70.0.3/32",friendlyname="varch.local (laptop)"} 0 wireguardreceivedbytestotal{interface="wg0",publickey="L2UoJZN7RmEKsMmqaJgKG0m1S2Zs2wd2ptAf+kb3008=",allowedips="10.70.0.4/32",friendlyname="cantarch"} 0 wireguardreceivedbytestotal{interface="wg0",publickey="MdVOIPKt9K2MPj/sO2NlWQbOnFJ6L/qX80mmhQwsUlA=",allowedips="10.70.0.50/32",friendlyname="frcognoarch"} 0 wireguardreceivedbytestotal{interface="wg0",publickey="lqYcojJMsIZXMUw1heAFbQHBoKjCEaeo7M1WXDh/KWc=",allowedips="10.70.0.40/32",friendlyname="frcognowin10"} 0 wireguardreceivedbytestotal{interface="wg0",publickey="928vO9Lf4+Mo84cWu4k1oRyzf0AR7FTGoPKHGoTMSHk=",allowedips="10.70.0.80/32",friendlyname="OnePlus 5T"} 0 wireguardreceivedbytestotal{interface="wg0",publickey="wTjv6hS6fKfNK+SzOLo7O6BQjEb6AD1TN9GjwZ08IwA=",allowedips="10.70.0.5/32",friendlyname="folioarch"} 0

HELP wireguardlatesthandshake_seconds Seconds from the last handshake

TYPE wireguardlatesthandshake_seconds gauge

wireguardlatesthandshakeseconds{interface="wg0",publickey="2S7mA0vEMethCNQrJpJKE81/JmhgtB+tHHLYQhgM6kk=",allowedips="10.70.0.2/32,10.70.0.66/32",friendlyname="OnePlus 6T"} 1562834127 wireguardlatesthandshakeseconds{interface="wg0",publickey="qnoxQoQI8KKMupLnSSureORV0wMmH7JryZNsmGVISzU=",allowedips="10.70.0.3/32",friendlyname="varch.local (laptop)"} 0 wireguardlatesthandshakeseconds{interface="wg0",publickey="L2UoJZN7RmEKsMmqaJgKG0m1S2Zs2wd2ptAf+kb3008=",allowedips="10.70.0.4/32",friendlyname="cantarch"} 0 wireguardlatesthandshakeseconds{interface="wg0",publickey="MdVOIPKt9K2MPj/sO2NlWQbOnFJ6L/qX80mmhQwsUlA=",allowedips="10.70.0.50/32",friendlyname="frcognoarch"} 0 wireguardlatesthandshakeseconds{interface="wg0",publickey="lqYcojJMsIZXMUw1heAFbQHBoKjCEaeo7M1WXDh/KWc=",allowedips="10.70.0.40/32",friendlyname="frcognowin10"} 0 wireguardlatesthandshakeseconds{interface="wg0",publickey="928vO9Lf4+Mo84cWu4k1oRyzf0AR7FTGoPKHGoTMSHk=",allowedips="10.70.0.80/32",friendlyname="OnePlus 5T"} 0 wireguardlatesthandshakeseconds{interface="wg0",publickey="wTjv6hS6fKfNK+SzOLo7O6BQjEb6AD1TN9GjwZ08IwA=",allowedips="10.70.0.5/32",friendlyname="folioarch"} 0 ```

In order for this to work, you need to add the friendly_name key value to the comments preceding a peer a specific metadata (in your wireguard configuration file). See below the [Peer] definition for an example. The tag is called friendly_name and it will be added to the entry exported to Prometheus. Note that this is not a standard but, since it's a comment, will not interfere with WireGuard in any way. For example this is how you edit your WireGuard configuration file:

```toml [Peer] PublicKey = lqYcojJMsIZXMUw1heAFbQHBoKjCEaeo7M1WXDh/KWc= AllowedIPs = 10.70.0.40/32

[Peer]

Custom comment

PublicKey = 928vO9Lf4+Mo84cWu4k1oRyzf0AR7FTGoPKHGoTMSHk= AllowedIPs = 10.70.0.80/32 ```

```toml [Peer]

friendly_name = frcognowin10

PublicKey = lqYcojJMsIZXMUw1heAFbQHBoKjCEaeo7M1WXDh/KWc= AllowedIPs = 10.70.0.40/32

[Peer]

friendly_name = OnePlus 5T

Custom comment

PublicKey = 928vO9Lf4+Mo84cWu4k1oRyzf0AR7FTGoPKHGoTMSHk= AllowedIPs = 10.70.0.80/32 ```

As you can see, all you need to do is to add the friendly name in the comments preceding a peer (and enable the flag since this feature is opt-in).

This is a sample of the label split mode:

```

HELP wireguardsentbytes_total Bytes sent to the peer

TYPE wireguardsentbytes_total counter

wireguardsentbytestotal{interface="wg0",publickey="2S7mA0vEMethCNQrJpJKE81/JmhgtB+tHHLYQhgM6kk=",allowedip0="10.70.0.2",allowedsubnet0="32",allowedip1="10.70.0.66",allowedsubnet1="32",friendlyname="OnePlus 6T"} 3208804 wireguardsentbytestotal{interface="wg0",publickey="qnoxQoQI8KKMupLnSSureORV0wMmH7JryZNsmGVISzU=",allowedip0="10.70.0.3",allowedsubnet0="32",friendlyname="varch.local (laptop)"} 0 wireguardsentbytestotal{interface="wg0",publickey="L2UoJZN7RmEKsMmqaJgKG0m1S2Zs2wd2ptAf+kb3008=",allowedip0="10.70.0.4",allowedsubnet0="32",friendlyname="cantarch"} 0 wireguardsentbytestotal{interface="wg0",publickey="MdVOIPKt9K2MPj/sO2NlWQbOnFJ6L/qX80mmhQwsUlA=",allowedip0="10.70.0.50",allowedsubnet0="32",friendlyname="frcognoarch"} 0 wireguardsentbytestotal{interface="wg0",publickey="lqYcojJMsIZXMUw1heAFbQHBoKjCEaeo7M1WXDh/KWc=",allowedip0="10.70.0.40",allowedsubnet0="32",friendlyname="frcognowin10"} 0 wireguardsentbytestotal{interface="wg0",publickey="928vO9Lf4+Mo84cWu4k1oRyzf0AR7FTGoPKHGoTMSHk=",allowedip0="10.70.0.80",allowedsubnet0="32",friendlyname="OnePlus 5T"} 0 wireguardsentbytestotal{interface="wg0",publickey="wTjv6hS6fKfNK+SzOLo7O6BQjEb6AD1TN9GjwZ08IwA=",allowedip0="10.70.0.5",allowedsubnet0="32",friendly_name="folioarch"} 0

HELP wireguardreceivedbytes_total Bytes received from the peer

TYPE wireguardreceivedbytes_total counter

wireguardreceivedbytestotal{interface="wg0",publickey="2S7mA0vEMethCNQrJpJKE81/JmhgtB+tHHLYQhgM6kk=",allowedip0="10.70.0.2",allowedsubnet0="32",allowedip1="10.70.0.66",allowedsubnet1="32",friendlyname="OnePlus 6T"} 71420072 wireguardreceivedbytestotal{interface="wg0",publickey="qnoxQoQI8KKMupLnSSureORV0wMmH7JryZNsmGVISzU=",allowedip0="10.70.0.3",allowedsubnet0="32",friendlyname="varch.local (laptop)"} 0 wireguardreceivedbytestotal{interface="wg0",publickey="L2UoJZN7RmEKsMmqaJgKG0m1S2Zs2wd2ptAf+kb3008=",allowedip0="10.70.0.4",allowedsubnet0="32",friendlyname="cantarch"} 0 wireguardreceivedbytestotal{interface="wg0",publickey="MdVOIPKt9K2MPj/sO2NlWQbOnFJ6L/qX80mmhQwsUlA=",allowedip0="10.70.0.50",allowedsubnet0="32",friendlyname="frcognoarch"} 0 wireguardreceivedbytestotal{interface="wg0",publickey="lqYcojJMsIZXMUw1heAFbQHBoKjCEaeo7M1WXDh/KWc=",allowedip0="10.70.0.40",allowedsubnet0="32",friendlyname="frcognowin10"} 0 wireguardreceivedbytestotal{interface="wg0",publickey="928vO9Lf4+Mo84cWu4k1oRyzf0AR7FTGoPKHGoTMSHk=",allowedip0="10.70.0.80",allowedsubnet0="32",friendlyname="OnePlus 5T"} 0 wireguardreceivedbytestotal{interface="wg0",publickey="wTjv6hS6fKfNK+SzOLo7O6BQjEb6AD1TN9GjwZ08IwA=",allowedip0="10.70.0.5",allowedsubnet0="32",friendly_name="folioarch"} 0

HELP wireguardlatesthandshake_seconds Seconds from the last handshake

TYPE wireguardlatesthandshake_seconds gauge

wireguardlatesthandshakeseconds{interface="wg0",publickey="2S7mA0vEMethCNQrJpJKE81/JmhgtB+tHHLYQhgM6kk=",allowedip0="10.70.0.2",allowedsubnet0="32",allowedip1="10.70.0.66",allowedsubnet1="32",friendlyname="OnePlus 6T"} 1562834127 wireguardlatesthandshakeseconds{interface="wg0",publickey="qnoxQoQI8KKMupLnSSureORV0wMmH7JryZNsmGVISzU=",allowedip0="10.70.0.3",allowedsubnet0="32",friendlyname="varch.local (laptop)"} 0 wireguardlatesthandshakeseconds{interface="wg0",publickey="L2UoJZN7RmEKsMmqaJgKG0m1S2Zs2wd2ptAf+kb3008=",allowedip0="10.70.0.4",allowedsubnet0="32",friendlyname="cantarch"} 0 wireguardlatesthandshakeseconds{interface="wg0",publickey="MdVOIPKt9K2MPj/sO2NlWQbOnFJ6L/qX80mmhQwsUlA=",allowedip0="10.70.0.50",allowedsubnet0="32",friendlyname="frcognoarch"} 0 wireguardlatesthandshakeseconds{interface="wg0",publickey="lqYcojJMsIZXMUw1heAFbQHBoKjCEaeo7M1WXDh/KWc=",allowedip0="10.70.0.40",allowedsubnet0="32",friendlyname="frcognowin10"} 0 wireguardlatesthandshakeseconds{interface="wg0",publickey="928vO9Lf4+Mo84cWu4k1oRyzf0AR7FTGoPKHGoTMSHk=",allowedip0="10.70.0.80",allowedsubnet0="32",friendlyname="OnePlus 5T"} 0 wireguardlatesthandshakeseconds{interface="wg0",publickey="wTjv6hS6fKfNK+SzOLo7O6BQjEb6AD1TN9GjwZ08IwA=",allowedip0="10.70.0.5",allowedsubnet0="32",friendly_name="folioarch"} 0 ```

Systemd service file

Now add the exporter to the Prometheus exporters as usual. I recommend to start it as a service. It's necessary to run it as root (if there is a non-root way to call wg show all dump please let me know). My systemd service file is like this one:

``` [Unit] Description=Prometheus WireGuard Exporter Wants=network-online.target After=network-online.target

[Service] User=root Group=root Type=simple ExecStart=/usr/local/bin/prometheuswireguardexporter -n /etc/wireguard/peers.conf -i wg0 -i wg1

[Install] WantedBy=multi-user.target ```