Welcome to our tutorial on how to monitor OpenVPN connections with Prometheus and Grafana. Grafana is a data visualization and monitoring tool and supports time series datastores such as Graphite, InfluxDB, Prometheus, Elasticsearch. Prometheus on the other hand is an open-source systems and service monitoring tool. It collects metrics from configured targets via HTTP calls at given intervals, evaluates rule expressions, displays the results, and can trigger alerts if some conditions are met. Grafana can be used to achieve better visualization of the metrics collected by the Prometheus. In this setup, however, we will learn how to collect OpenVPN connection metrics using Prometheus and visualize then on Grafana.

Monitor OpenVPN Connections with Prometheus and Grafana
In this tutorial, we are using an Ubuntu 20.04 systems for demo labs. Feel free to use other OSes.
To monitor OpenVPN connections with Prometheus and Grafana, we will install and setup each component of the monitoring separately.
Install Prometheus on Ubuntu 20.04
We have covered the installation of Prometheus on Ubuntu 20.04 in our previous guide. Follow the link below to install and setup Prometheus on Ubuntu 20.04;
Install and Setup Prometheus on Ubuntu 20.04
You can as well use CentOS 8 instead.
Install and Configure Prometheus on CentOS 8
Install Grafana on Ubuntu 20.04
Follow the link below to install Grafana on Ubuntu 20.04;
Installing Grafana on Ubuntu 20.04
Want to use CentOS instead? Follow the link below to setup Grafana on CentOS 8.
Install Latest Grafana on CentOS 8
Integrating Grafana with Prometheus
Once both Grafana and Prometheus are in place, you can then configure Grafana to fetch the metrics from Prometheus.
systemctl status grafana-server
● grafana-server.service - Grafana instance
Loaded: loaded (/lib/systemd/system/grafana-server.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2020-09-21 17:01:07 UTC; 5min ago
Docs: http://docs.grafana.org
Main PID: 14610 (grafana-server)
Tasks: 8 (limit: 2282)
Memory: 18.0M
CGroup: /system.slice/grafana-server.service
└─14610 /usr/sbin/grafana-server --config=/etc/grafana/grafana.ini --pidfile=/var/run/grafana/grafana-server.pid --packaging=deb cfg:default.paths.logs=/var/l>
Sep 21 17:02:16 ubuntu20 grafana-server[14610]: t=2020-09-21T17:02:16+0000 lvl=info msg="Executing migration" logger=migrator id="create cache_data table"
...
systemctl status prometheus
● prometheus.service - Prometheus Time Series Collection and Processing Server
Loaded: loaded (/etc/systemd/system/prometheus.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2020-09-21 16:35:03 UTC; 32min ago
Main PID: 2464 (prometheus)
Tasks: 8 (limit: 2282)
Memory: 27.6M
CGroup: /system.slice/prometheus.service
└─2464 /usr/local/bin/prometheus --config.file /etc/prometheus/prometheus.yml --storage.tsdb.path /var/lib/prometheus/ --web.console.templates=/etc/prometheus>
Sep 21 16:35:03 ubuntu20 prometheus[2464]: level=info ts=2020-09-21T16:35:03.205Z caller=head.go:644 component=tsdb msg="Replaying on-disk memory
...
ss -altnp | grep -E ":3000|:9090"
LISTEN 0 4096 *:9090 *:* users:(("prometheus",pid=2464,fd=10))
LISTEN 0 4096 *:3000 *:* users:(("grafana-server",pid=14610,fd=8))
To integrate Grafana with Prometheus, you need to add Prometheus data source to Grafana.
This can be done by logging into Grafana web interface and navigating to Configuration (gear like icon) > Datasources > Add data source.
From the data source types, select Prometheus. This opens up Prometheus datasource configuration page.
Enter the Prometheus server URL. If you are running Grafana and Prometheus on the same server, use the address http://localhost:9090 otherwise, use the address http://<prometheus-server-IP>:9090.
Click Save & Test.

Install OpenVPN Prometheus Node Exporter on OpenVPN Server
Next, you need to install OpenVPN node exporter on the OpenVPN Server.
We have already covered how to install and configure OpenVPN and OpenVPN clients;
Install and Setup OpenVPN Server on Ubuntu 20.04
Install and Configure OpenVPN Client on CentOS 8/Ubuntu 18.04
Setup OpenVPN Server on CentOS 8
In this setup, our OpenVPN server is running on a CentOS 8 system. Hence, we need to install the OpenVPN node exporter on CentOS 8 OpenVPN server. OpenVPN Exporter for Prometheus is an open source project hosted on Github and written by Kumina. All credit goes back to the creator of this exporter.
You can run the exporter as docker container or a standalone executable binary.
In this setup, we run it as standalone executable binary on a Centos 8 server hosting a vpn server.
Install Go on CentOS 8
Download Go tarball for installation from Go download’s page.
wget https://golang.org/dl/go1.15.2.linux-amd64.tar.gz
Extract it into /usr/local, creating a Go tree in /usr/local/go.
tar -C /usr/local -xzf go1.15.2.linux-amd64.tar.gz
Add /usr/local/go/bin to the PATH
environment variable.
vim .bashrc_profile
...
# User specific environment and startup programs
PATH=$PATH:$HOME/bin:/usr/local/go/bin
export PATH
Source the file to effect the changes.
source .bash_profile
Go should now be on your PATH.
Download OpenVPN Node Exporter
Download OpenVPN node exporter from the Github releases page.
wget https://github.com/kumina/openvpn_exporter/archive/v0.3.0.tar.gz
Extract it;
tar xzf v0.3.0.tar.gz
Next, build the OpenVPN node exporter;
cd openvpn_exporter-0.3.0/
Set the path to OpenVPN server status log file;
vim main.og
...
func main() {
var (
listenAddress = flag.String("web.listen-address", ":9176", "Address to listen on for web interface and telemetry.")
metricsPath = flag.String("web.telemetry-path", "/metrics", "Path under which to expose metrics.")
// openvpnStatusPaths = flag.String("openvpn.status_paths", "examples/client.status,examples/server2.status,examples/server3.status", "Paths at which OpenVPN places its status files.")
openvpnStatusPaths = flag.String("openvpn.status_paths", "/var/log/openvpn/openvpn-status.log", "Paths at which OpenVPN places its status files.")
...
Save and exit the file.
Build the exporter now;
go build -o openvpn_exporter main.go
This will create Prometheus OpenVPN node exporter binary, openvpn_eporter
, in the current directory. Copy the binary to /usr/local/bin binary path.
cp openvpn_eporter /usr/local/bin/
By default, the exporter listens on TCP port 9176, hence you need to open this port on firewall.
firewall-cmd --add-port=9176/tcp --permanent
firewall-cmd --reload
Run the exporter in standalone mode to test it;
openvpn_exporter
2020/09/21 23:37:50 Starting OpenVPN Exporter
2020/09/21 23:37:50 Listen address: :9176
2020/09/21 23:37:50 Metrics path: /metrics
2020/09/21 23:37:50 openvpn.status_path: /var/log/openvpn/openvpn-status.log
2020/09/21 23:37:50 Ignore Individuals: false
Configure Prometheus to scrape OpenVPN Node exporter metrics;
vim /etc/prometheus/prometheus.yml
...
# The job name is added as a label `job=` to any timeseries scraped from this config.
- job_name: 'prometheus'
# metrics_path defaults to '/metrics'
# scheme defaults to 'http'.
static_configs:
- targets: ['localhost:9090']
## Add OpenVPN Node Exporter
- job_name: 'openvpn-metrics'
scrape_interval: 5s
static_configs:
- targets: ['192.168.60.6:9176']
Restart Prometheus;
systemctl restart prometheus
Check the Prometheus Target, http://server-IP:9090/targets
.

Monitor OpenVPN Connections with Prometheus and Grafana
Create OpenVPN Node Exporter Visualization on Grafana
You can create your own visualization dashboards or utilize the community created dashboards. For example, we use Grafana OpenVPN node exporter visualization dashboard from the Grafana community.
To import this dashboard, navigate to http://grafana-server-IP:3000/dashboard/import
.
Paste the dashboard ID or JSON file, load and import it.
For instance, we took the the community dashboard from https://grafana.com/grafana/dashboards/10562
and modified it to fit our needs.
After modifying the above dashboard, this is how our simple OpenVPN connections dashabaord looks like;

The JSON file for the above dashboard is provided below (modified version of dashboard 10562
, all credit goes back to original author);
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"description": "OpenVPN Server status using Prometheus and OpenVPN exporter ",
"editable": true,
"gnetId": 10562,
"graphTooltip": 0,
"id": 3,
"links": [
{
"icon": "external link",
"tags": [
"openvpn"
],
"targetBlank": true,
"type": "dashboards"
}
],
"panels": [
{
"cacheTimeout": null,
"colorBackground": false,
"colorPostfix": false,
"colorPrefix": false,
"colorValue": true,
"colors": [
"#d44a3a",
"rgba(237, 129, 40, 0.89)",
"#299c46"
],
"datasource": "Prometheus",
"fieldConfig": {
"defaults": {
"custom": {}
},
"overrides": []
},
"format": "none",
"gauge": {
"maxValue": 256,
"minValue": 0,
"show": false,
"thresholdLabels": false,
"thresholdMarkers": true
},
"gridPos": {
"h": 2,
"w": 3,
"x": 0,
"y": 0
},
"id": 2,
"interval": null,
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"pluginVersion": "6.2.0-beta2",
"postfix": " Clients",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "50%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": true,
"lineColor": "#5794F2",
"show": true
},
"tableColumn": "openvpn_server_connected_clients{instance=\"192.168.60.6:9176\", job=\"openvpn-metrics\", status_path=\"/var/log/openvpn/openvpn-status.log\"}",
"targets": [
{
"expr": "openvpn_server_connected_clients",
"format": "time_series",
"instant": true,
"interval": "",
"intervalFactor": 1,
"legendFormat": "",
"refId": "A"
}
],
"thresholds": "0, 30",
"timeFrom": null,
"timeShift": null,
"title": "",
"type": "singlestat",
"valueFontSize": "150%",
"valueMaps": [
{
"op": "=",
"text": "N/A",
"value": "null"
},
{
"op": "=",
"text": "No",
"value": "0"
}
],
"valueName": "current"
},
{
"cacheTimeout": null,
"colorBackground": false,
"colorPostfix": false,
"colorPrefix": false,
"colorValue": true,
"colors": [
"#FF9830",
"#5794F2",
"#5794F2"
],
"datasource": "Prometheus",
"fieldConfig": {
"defaults": {
"custom": {}
},
"overrides": []
},
"format": "none",
"gauge": {
"maxValue": 256,
"minValue": 0,
"show": false,
"thresholdLabels": false,
"thresholdMarkers": true
},
"gridPos": {
"h": 2,
"w": 3,
"x": 3,
"y": 0
},
"id": 16,
"interval": null,
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"pluginVersion": "6.2.0-beta2",
"postfix": " Users",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "50%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": true,
"lineColor": "#5794F2",
"show": true
},
"tableColumn": "",
"targets": [
{
"expr": "count(openvpn_server_client_received_bytes_total{common_name=~\"[a-zA-Z0-9]+\"}) or absent(count(openvpn_server_client_received_bytes_total{common_name=~\"[a-zA-Z0-9]+\"}))-1",
"format": "time_series",
"instant": true,
"interval": "",
"intervalFactor": 1,
"legendFormat": "",
"refId": "A"
}
],
"thresholds": "1, 2",
"timeFrom": null,
"timeShift": null,
"title": "",
"type": "singlestat",
"valueFontSize": "150%",
"valueMaps": [],
"valueName": "current"
},
{
"cacheTimeout": null,
"colorBackground": false,
"colorPrefix": false,
"colorValue": true,
"colors": [
"#d44a3a",
"rgba(237, 129, 40, 0.89)",
"#299c46"
],
"datasource": "Prometheus",
"decimals": null,
"fieldConfig": {
"defaults": {
"custom": {}
},
"overrides": []
},
"format": "none",
"gauge": {
"maxValue": 100,
"minValue": 0,
"show": false,
"thresholdLabels": false,
"thresholdMarkers": true
},
"gridPos": {
"h": 2,
"w": 7,
"x": 6,
"y": 0
},
"id": 12,
"interval": null,
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"postfix": "",
"postfixFontSize": "50%",
"prefix": "Status:",
"prefixFontSize": "150%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": false,
"lineColor": "rgb(31, 120, 193)",
"show": false
},
"tableColumn": "openvpn_up{instance=\"192.168.60.6:9176\", job=\"openvpn-metrics\", status_path=\"/var/log/openvpn/openvpn-status.log\"}",
"targets": [
{
"expr": "openvpn_up{job=\"openvpn-metrics\"}",
"format": "time_series",
"instant": true,
"intervalFactor": 1,
"legendFormat": "",
"refId": "A"
}
],
"thresholds": "1, 1",
"timeFrom": null,
"timeShift": null,
"title": "",
"type": "singlestat",
"valueFontSize": "150%",
"valueMaps": [
{
"op": "=",
"text": "N/A",
"value": "null"
},
{
"op": "=",
"text": "UP",
"value": "1"
},
{
"op": "=",
"text": "DOWN",
"value": "0"
}
],
"valueName": "current"
},
{
"aliasColors": {},
"bars": false,
"cacheTimeout": null,
"dashLength": 10,
"dashes": false,
"datasource": "Prometheus",
"decimals": 0,
"fieldConfig": {
"defaults": {
"custom": {}
},
"overrides": []
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 7,
"w": 11,
"x": 13,
"y": 0
},
"hiddenSeries": false,
"id": 14,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": false,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null as zero",
"percentage": false,
"pluginVersion": "7.1.5",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "sum(openvpn_server_connected_clients)",
"format": "time_series",
"instant": false,
"interval": "",
"intervalFactor": 1,
"legendFormat": "Connected OpenVPN Clients",
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Clients Connected",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"decimals": 0,
"format": "short",
"label": "Clients",
"logBase": 1,
"max": null,
"min": "0",
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"cacheTimeout": null,
"colorBackground": false,
"colorPrefix": false,
"colorValue": true,
"colors": [
"#5794F2",
"#5794F2",
"#5794F2"
],
"datasource": "Prometheus",
"decimals": 2,
"fieldConfig": {
"defaults": {
"custom": {}
},
"overrides": []
},
"format": "bytes",
"gauge": {
"maxValue": 100,
"minValue": 0,
"show": false,
"thresholdLabels": false,
"thresholdMarkers": true
},
"gridPos": {
"h": 2,
"w": 6,
"x": 0,
"y": 2
},
"hideTimeOverride": true,
"id": 19,
"interval": null,
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"postfix": " sent today",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "50%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": false,
"lineColor": "rgb(31, 120, 193)",
"show": false
},
"tableColumn": "",
"targets": [
{
"expr": "sum(increase(openvpn_server_client_sent_bytes_total[1d]))",
"format": "time_series",
"instant": true,
"intervalFactor": 1,
"refId": "A"
}
],
"thresholds": "1, 2",
"timeFrom": "24h",
"timeShift": null,
"title": "",
"type": "singlestat",
"valueFontSize": "80%",
"valueMaps": [
{
"op": "=",
"text": "N/A",
"value": "null"
}
],
"valueName": "current"
},
{
"cacheTimeout": null,
"colorBackground": false,
"colorPostfix": false,
"colorPrefix": false,
"colorValue": true,
"colors": [
"#FF9830",
"#5794F2",
"#5794F2"
],
"datasource": "Prometheus",
"fieldConfig": {
"defaults": {
"custom": {}
},
"overrides": []
},
"format": "none",
"gauge": {
"maxValue": 256,
"minValue": 0,
"show": false,
"thresholdLabels": false,
"thresholdMarkers": true
},
"gridPos": {
"h": 5,
"w": 3,
"x": 6,
"y": 2
},
"id": 15,
"interval": null,
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"pluginVersion": "6.2.0-beta2",
"postfix": " Servers",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "50%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": true,
"lineColor": "#5794F2",
"show": true
},
"tableColumn": "",
"targets": [
{
"expr": "count(openvpn_server_connected_clients{instance=~\"[0-9].+:[0-9]{0,}\"}) or absent(count(openvpn_server_connected_clients{instance=~\"[0-9].+:[0-9]{0,}\"}))-1",
"format": "time_series",
"instant": true,
"interval": "",
"intervalFactor": 1,
"legendFormat": "",
"refId": "A"
}
],
"thresholds": "1, 2",
"timeFrom": null,
"timeShift": null,
"title": "",
"type": "singlestat",
"valueFontSize": "150%",
"valueMaps": [
{
"op": "=",
"text": "0",
"value": "null"
},
{
"op": "=",
"text": "0",
"value": "0"
}
],
"valueName": "current"
},
{
"cacheTimeout": null,
"colorBackground": false,
"colorPostfix": false,
"colorValue": true,
"colors": [
"#299c46",
"rgba(237, 129, 40, 0.89)",
"#d44a3a"
],
"datasource": "Prometheus",
"decimals": 0,
"fieldConfig": {
"defaults": {
"custom": {}
},
"overrides": []
},
"format": "none",
"gauge": {
"maxValue": 100,
"minValue": 0,
"show": false,
"thresholdLabels": false,
"thresholdMarkers": true
},
"gridPos": {
"h": 5,
"w": 4,
"x": 9,
"y": 2
},
"id": 10,
"interval": null,
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"postfix": "s since status update",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "30%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": false,
"lineColor": "rgb(31, 120, 193)",
"show": false
},
"tableColumn": "{instance=\"192.168.60.6:9176\", job=\"openvpn-metrics\", status_path=\"/var/log/openvpn/openvpn-status.log\"}",
"targets": [
{
"expr": "time()-openvpn_status_update_time_seconds{job=\"openvpn-metrics\"}",
"format": "time_series",
"instant": true,
"intervalFactor": 1,
"refId": "A"
}
],
"thresholds": "120, 180",
"timeFrom": null,
"timeShift": null,
"title": "",
"type": "singlestat",
"valueFontSize": "150%",
"valueMaps": [
{
"op": "=",
"text": "N/A",
"value": "null"
}
],
"valueName": "current"
},
{
"cacheTimeout": null,
"colorBackground": false,
"colorValue": true,
"colors": [
"#5794F2",
"#5794F2",
"#5794F2"
],
"datasource": "Prometheus",
"decimals": 2,
"fieldConfig": {
"defaults": {
"custom": {}
},
"overrides": []
},
"format": "bytes",
"gauge": {
"maxValue": 100,
"minValue": 0,
"show": false,
"thresholdLabels": false,
"thresholdMarkers": true
},
"gridPos": {
"h": 3,
"w": 6,
"x": 0,
"y": 4
},
"hideTimeOverride": true,
"id": 18,
"interval": null,
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"postfix": " received today",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "50%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": false,
"lineColor": "rgb(31, 120, 193)",
"show": false
},
"tableColumn": "",
"targets": [
{
"expr": "sum(increase(openvpn_server_client_received_bytes_total[1d]))",
"format": "time_series",
"instant": true,
"intervalFactor": 1,
"refId": "A"
}
],
"thresholds": "1, 2",
"timeFrom": "24h",
"timeShift": null,
"title": "",
"type": "singlestat",
"valueFontSize": "80%",
"valueMaps": [
{
"op": "=",
"text": "N/A",
"value": "null"
}
],
"valueName": "current"
},
{
"columns": [],
"datasource": "Prometheus",
"fieldConfig": {
"defaults": {
"custom": {}
},
"overrides": []
},
"fontSize": "100%",
"gridPos": {
"h": 10,
"w": 24,
"x": 0,
"y": 7
},
"id": 4,
"links": [],
"pageSize": 100,
"scroll": true,
"showHeader": true,
"sort": {
"col": 4,
"desc": false
},
"styles": [
{
"alias": "Time",
"align": "auto",
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"pattern": "Time",
"type": "hidden"
},
{
"alias": "Username",
"align": "auto",
"colorMode": null,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"decimals": 2,
"pattern": "common_name",
"thresholds": [],
"type": "string",
"unit": "short"
},
{
"alias": "Login Time",
"align": "auto",
"colorMode": null,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": null,
"mappingType": 1,
"pattern": "connection_time",
"thresholds": [],
"type": "date",
"unit": "dateTimeFromNow"
},
{
"alias": "VPN Client Address",
"align": "auto",
"colorMode": null,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 2,
"mappingType": 1,
"pattern": "virtual_address",
"thresholds": [],
"type": "string",
"unit": "short"
},
{
"alias": "",
"align": "auto",
"colorMode": null,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 2,
"mappingType": 1,
"pattern": "Value",
"thresholds": [],
"type": "hidden",
"unit": "short"
},
{
"alias": "Rx",
"align": "auto",
"colorMode": null,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 0,
"mappingType": 1,
"pattern": "Value #A",
"thresholds": [],
"type": "number",
"unit": "bytes"
},
{
"alias": "Tx",
"align": "auto",
"colorMode": null,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 0,
"mappingType": 1,
"pattern": "Value #B",
"thresholds": [],
"type": "number",
"unit": "bytes"
},
{
"alias": "Real Client Address",
"align": "auto",
"colorMode": null,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 2,
"mappingType": 1,
"pattern": "real_address",
"thresholds": [],
"type": "string",
"unit": "short"
}
],
"targets": [
{
"expr": "sort_desc(sum(label_replace(openvpn_server_client_received_bytes_total{common_name!=\"UNDEF\"}, \"connection_time\", \"${1}000\", \"connection_time\", \"(.*)\"))by(common_name, connection_time, virtual_address, real_address))",
"format": "table",
"instant": true,
"interval": "",
"intervalFactor": 1,
"legendFormat": "",
"refId": "A"
},
{
"expr": "sum(label_replace(openvpn_server_client_sent_bytes_total{common_name!=\"UNDEF\"}, \"connection_time\", \"${1}000\", \"connection_time\", \"(.*)\"))by(common_name, connection_time, virtual_address, real_address)",
"format": "table",
"instant": true,
"interval": "",
"intervalFactor": 1,
"legendFormat": "",
"refId": "B"
}
],
"timeFrom": null,
"timeShift": null,
"title": "Current OpenVPN Clients",
"transform": "table",
"type": "table-old"
}
],
"refresh": false,
"schemaVersion": 26,
"style": "dark",
"tags": [
"openvpn"
],
"templating": {
"list": []
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
},
"timezone": "",
"title": "1 OpenVPN Server",
"uid": "_1DM17HWk",
"version": 4
}
The dashboard requires pie-chart plugin.
Install Grafana Pie Chart Plugin by executing the command below;
grafana-cli plugins install grafana-piechart-panel
Running OpenVPN Node Exporter as a Service
Create a systemd service for the OpenVPN Prometheus node exporter.
vim /etc/systemd/system/openvpn_exporter.service
[Unit]
Description=Prometheus OpenVPN Node Exporter
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/openvpn_exporter
[Install]
WantedBy=multi-user.target
Reload the systemd manager configuration.
systemctl daemon-reload
Start and enable Node Exporter to run on system boot.
systemctl enable --now openvpn_exporter.service
Check the status;
systemctl status openvpn_exporter
● openvpn_exporter.service - Prometheus OpenVPN Node Exporter
Loaded: loaded (/etc/systemd/system/openvpn_exporter.service; enabled; vendor preset: disabled)
Active: active (running) since Tue 2020-09-22 22:56:01 EAT; 13s ago
Main PID: 5391 (openvpn_exporte)
Tasks: 4 (limit: 23968)
Memory: 9.1M
CGroup: /system.slice/openvpn_exporter.service
└─5391 /usr/local/bin/openvpn_exporter
Sep 22 22:56:01 centos8.kifarunix-demo.com systemd[1]: Stopped Prometheus OpenVPN Node Exporter.
Sep 22 22:56:01 centos8.kifarunix-demo.com systemd[1]: Started Prometheus OpenVPN Node Exporter.
Sep 22 22:56:01 centos8.kifarunix-demo.com openvpn_exporter[5391]: 2020/09/22 22:56:01 Starting OpenVPN Exporter
Sep 22 22:56:01 centos8.kifarunix-demo.com openvpn_exporter[5391]: 2020/09/22 22:56:01 Listen address: :9176
Sep 22 22:56:01 centos8.kifarunix-demo.com openvpn_exporter[5391]: 2020/09/22 22:56:01 Metrics path: /metrics
Sep 22 22:56:01 centos8.kifarunix-demo.com openvpn_exporter[5391]: 2020/09/22 22:56:01 openvpn.status_path: /var/log/openvpn/openvpn-status.log
Sep 22 22:56:01 centos8.kifarunix-demo.com openvpn_exporter[5391]: 2020/09/22 22:56:01 Ignore Individuals: false
Your OpenVPN connection status should be scrapped automatically.
That marks the end of our guide on how to monitor OpenVPN Connections with Prometheus and Grafana.
Other Related Tutorials
Install and Configure Prometheus on CentOS 8
Install and Configure Prometheus on Fedora 29/Fedora 28
Install and Configure Prometheus on Debian 9
Hi
Thanks for sharing this tutorial, I would like to know how is the init of openvpn @ server on your server?
I configured the openvpn exporter, but it doesn’t export any metrics, could you tell me if you have to change anything at the server start?
Thanks a lot, that works perfect. love u
Hello,
thanks for sharing this tutorial. Currently iam facing one issue, can someone tell me what I did wrong ?
this is my error launching the exporter 2021/08/20 12:03:31 Failed to scrape showq socket: unexpected file contents: “OpenVPN CLIENT LIS”
Hi, did you try this guide already?
root@ip-172-27-184-101:~# systemctl status openvpn_exporter
● openvpn_exporter.service – Prometheus OpenVPN Node Exporter
Loaded: loaded (/etc/systemd/system/openvpn_exporter.service; enabled; vendor preset: enabled)
Active: failed (Result: exit-code) since Mon 2022-11-07 11:36:41 UTC; 1min 39s ago
Main PID: 21044 (code=exited, status=203/EXEC)
Nov 07 11:36:41 ip-172-27-184-101 systemd[1]: Started Prometheus OpenVPN Node Exporter.
Nov 07 11:36:41 ip-172-27-184-101 systemd[21044]: openvpn_exporter.service: Failed to execute command: No such file or directory
Nov 07 11:36:41 ip-172-27-184-101 systemd[21044]: openvpn_exporter.service: Failed at step EXEC spawning /usr/local/bin/openvpn_exporter: No suc
Nov 07 11:36:41 ip-172-27-184-101 systemd[1]: openvpn_exporter.service: Main process exited, code=exited, status=203/EXEC
Nov 07 11:36:41 ip-172-27-184-101 systemd[1]: openvpn_exporter.service: Failed with result ‘exit-code’.