Set up comprehensive monitoring for your OpenVPN server using Prometheus to collect connection metrics and Grafana to visualize client connections, bandwidth usage, and server performance through custom dashboards.
Prerequisites
- OpenVPN server installed and configured
- Root or sudo access
- At least 2GB RAM
- Basic knowledge of Prometheus and Grafana
What this solves
OpenVPN monitoring helps you track client connections, bandwidth usage, and server performance in real-time. This tutorial shows you how to export OpenVPN status data to Prometheus and create comprehensive Grafana dashboards for VPN infrastructure monitoring.
Step-by-step installation
Update system packages
Start by updating your package manager to ensure you get the latest versions of monitoring tools.
sudo apt update && sudo apt upgrade -y
Install required dependencies
Install Python and required packages for the OpenVPN Prometheus exporter.
sudo apt install -y python3 python3-pip git wget curl
Configure OpenVPN status logging
Enable OpenVPN status logging to generate metrics data. Edit your OpenVPN server configuration to include status file output.
# Add these lines to enable status monitoring
status /var/log/openvpn/openvpn-status.log 10
status-version 2
management localhost 7505
Create OpenVPN log directory
Create the log directory with proper permissions for OpenVPN status files.
sudo mkdir -p /var/log/openvpn
sudo chown nobody:nogroup /var/log/openvpn
sudo chmod 755 /var/log/openvpn
Restart OpenVPN service
Restart OpenVPN to apply the new configuration and start generating status logs.
sudo systemctl restart openvpn@server
sudo systemctl status openvpn@server
Install Prometheus
Download and install Prometheus server to collect and store OpenVPN metrics.
cd /tmp
wget https://github.com/prometheus/prometheus/releases/download/v2.45.0/prometheus-2.45.0.linux-amd64.tar.gz
tar xvfz prometheus-2.45.0.linux-amd64.tar.gz
sudo mv prometheus-2.45.0.linux-amd64 /opt/prometheus
sudo useradd --no-create-home --shell /bin/false prometheus
Create Prometheus directories
Set up directory structure and permissions for Prometheus configuration and data storage.
sudo mkdir -p /etc/prometheus /var/lib/prometheus
sudo chown prometheus:prometheus /etc/prometheus /var/lib/prometheus
sudo chown prometheus:prometheus /opt/prometheus/prometheus /opt/prometheus/promtool
Create Prometheus configuration
Configure Prometheus to scrape OpenVPN metrics from the exporter we'll set up next.
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
# - "first_rules.yml"
# - "second_rules.yml"
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'openvpn'
static_configs:
- targets: ['localhost:9176']
scrape_interval: 10s
metrics_path: /metrics
Create Prometheus systemd service
Set up systemd service for automatic Prometheus startup and management.
[Unit]
Description=Prometheus
Wants=network-online.target
After=network-online.target
[Service]
User=prometheus
Group=prometheus
Type=simple
ExecStart=/opt/prometheus/prometheus \
--config.file /etc/prometheus/prometheus.yml \
--storage.tsdb.path /var/lib/prometheus/ \
--web.console.templates=/opt/prometheus/consoles \
--web.console.libraries=/opt/prometheus/console_libraries \
--web.listen-address=0.0.0.0:9090
[Install]
WantedBy=multi-user.target
Install OpenVPN Prometheus exporter
Clone and install the OpenVPN Prometheus exporter to convert status logs into Prometheus metrics.
cd /opt
sudo git clone https://github.com/kumina/openvpn_exporter.git
cd openvpn_exporter
sudo pip3 install -r requirements.txt
Create OpenVPN exporter systemd service
Configure the OpenVPN exporter as a systemd service for automatic startup and monitoring.
[Unit]
Description=OpenVPN Prometheus Exporter
After=network.target
[Service]
Type=simple
User=nobody
Group=nogroup
ExecStart=/usr/bin/python3 /opt/openvpn_exporter/openvpn_exporter.py \
--openvpn.status-paths /var/log/openvpn/openvpn-status.log \
--web.listen-address 0.0.0.0:9176
Restart=always
RestartSec=15
[Install]
WantedBy=multi-user.target
Set proper permissions
Configure file ownership and permissions for the Prometheus configuration.
sudo chown prometheus:prometheus /etc/prometheus/prometheus.yml
sudo chown -R nobody:nogroup /opt/openvpn_exporter
Start monitoring services
Enable and start both Prometheus and the OpenVPN exporter services.
sudo systemctl daemon-reload
sudo systemctl enable --now prometheus
sudo systemctl enable --now openvpn-exporter
sudo systemctl status prometheus
sudo systemctl status openvpn-exporter
Install Grafana
Add the Grafana repository and install Grafana for dashboard visualization.
sudo apt install -y software-properties-common
wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add -
echo "deb https://packages.grafana.com/oss/deb stable main" | sudo tee /etc/apt/sources.list.d/grafana.list
sudo apt update
sudo apt install -y grafana
Configure Grafana
Set up basic Grafana configuration with security settings and domain configuration.
[server]
http_addr = 0.0.0.0
http_port = 3000
domain = example.com
[security]
admin_user = admin
admin_password = your_secure_password_here
[users]
allow_sign_up = false
allow_org_create = false
Start Grafana service
Enable and start the Grafana service for dashboard access.
sudo systemctl enable --now grafana-server
sudo systemctl status grafana-server
Configure firewall rules
Open necessary ports for Prometheus, Grafana, and the OpenVPN exporter.
sudo ufw allow 3000/tcp comment 'Grafana'
sudo ufw allow 9090/tcp comment 'Prometheus'
sudo ufw allow 9176/tcp comment 'OpenVPN Exporter'
Configure Grafana dashboards
Add Prometheus data source
Access Grafana at http://your-server-ip:3000 and add Prometheus as a data source. Navigate to Configuration > Data Sources > Add data source > Prometheus.
URL: http://localhost:9090
Access: Server (default)
HTTP Method: GET
Create OpenVPN dashboard
Create a new dashboard with panels to monitor OpenVPN connections and performance metrics.
# Connected clients count
openvpn_up
Client connection status
openvpn_client_connected
Bytes received per client
rate(openvpn_client_bytes_received_total[5m])
Bytes sent per client
rate(openvpn_client_bytes_sent_total[5m])
Server uptime
openvpn_server_connected
Configure dashboard panels
Set up specific panels for comprehensive OpenVPN monitoring with appropriate visualization types.
| Panel Type | Query | Description |
|---|---|---|
| Stat | openvpn_up | Server status (up/down) |
| Stat | count(openvpn_client_connected == 1) | Connected clients count |
| Time Series | rate(openvpn_client_bytes_received_total[5m]) * 8 | Download bandwidth (bps) |
| Time Series | rate(openvpn_client_bytes_sent_total[5m]) * 8 | Upload bandwidth (bps) |
| Table | openvpn_client_connected | Client connection details |
Set up alerting
Configure Prometheus alerting rules
Create alerting rules for OpenVPN monitoring to notify about connection issues.
groups:
- name: openvpn
rules:
- alert: OpenVPNDown
expr: openvpn_up == 0
for: 1m
labels:
severity: critical
annotations:
summary: "OpenVPN server is down"
description: "OpenVPN server has been down for more than 1 minute"
- alert: HighClientCount
expr: count(openvpn_client_connected == 1) > 50
for: 5m
labels:
severity: warning
annotations:
summary: "High number of VPN connections"
description: "More than 50 clients connected to VPN server"
Update Prometheus configuration
Add the alerting rules to your Prometheus configuration.
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
- "openvpn-rules.yml"
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'openvpn'
static_configs:
- targets: ['localhost:9176']
scrape_interval: 10s
metrics_path: /metrics
Restart Prometheus
Restart Prometheus to load the new alerting rules.
sudo chown prometheus:prometheus /etc/prometheus/openvpn-rules.yml
sudo systemctl restart prometheus
sudo systemctl status prometheus
Verify your setup
# Check OpenVPN status log generation
sudo tail -f /var/log/openvpn/openvpn-status.log
Verify Prometheus is collecting metrics
curl http://localhost:9176/metrics | grep openvpn
Check Prometheus targets
curl http://localhost:9090/api/v1/targets
Verify services are running
sudo systemctl status openvpn@server prometheus openvpn-exporter grafana-server
Access your monitoring interfaces:
- Grafana dashboard:
http://your-server-ip:3000 - Prometheus web interface:
http://your-server-ip:9090 - OpenVPN exporter metrics:
http://your-server-ip:9176/metrics
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| No metrics from exporter | Status log not generated | Check OpenVPN config includes status directive |
| Exporter connection failed | Permission issues with log file | sudo chown nobody:nogroup /var/log/openvpn/openvpn-status.log |
| Prometheus can't scrape targets | Firewall blocking ports | Ensure ports 9090, 9176, 3000 are open |
| Grafana shows no data | Prometheus data source misconfigured | Verify Prometheus URL is http://localhost:9090 |
| Old metrics displayed | OpenVPN status file not updating | Restart OpenVPN service and check status interval |
Next steps
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# OpenVPN Prometheus Monitoring Stack Installer
# Installs and configures OpenVPN monitoring with Prometheus and Grafana
# Colors for output
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly NC='\033[0m'
# Global variables
PROMETHEUS_VERSION="2.45.0"
OPENVPN_SERVICE="openvpn@server"
# Usage function
usage() {
echo "Usage: $0 [OPTIONS]"
echo "Options:"
echo " --openvpn-service <name> OpenVPN service name (default: openvpn@server)"
echo " -h, --help Show this help message"
exit 1
}
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
--openvpn-service)
OPENVPN_SERVICE="$2"
shift 2
;;
-h|--help)
usage
;;
*)
echo -e "${RED}Error: Unknown option $1${NC}"
usage
;;
esac
done
# Error handler for cleanup
cleanup_on_error() {
echo -e "${RED}Error occurred during installation. Cleaning up...${NC}"
systemctl stop prometheus 2>/dev/null || true
systemctl stop openvpn-exporter 2>/dev/null || true
systemctl disable prometheus 2>/dev/null || true
systemctl disable openvpn-exporter 2>/dev/null || true
rm -rf /opt/prometheus /opt/openvpn_exporter 2>/dev/null || true
userdel prometheus 2>/dev/null || true
exit 1
}
trap cleanup_on_error ERR
# Check prerequisites
check_prerequisites() {
if [[ $EUID -ne 0 ]]; then
echo -e "${RED}Error: This script must be run as root${NC}"
exit 1
fi
if ! systemctl is-active --quiet "$OPENVPN_SERVICE"; then
echo -e "${YELLOW}Warning: OpenVPN service $OPENVPN_SERVICE is not running${NC}"
echo "Please ensure OpenVPN is properly configured"
fi
}
# Detect distribution and package manager
detect_distro() {
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_INSTALL="apt install -y"
PKG_UPDATE="apt update && apt upgrade -y"
NOBODY_GROUP="nogroup"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_INSTALL="dnf install -y"
PKG_UPDATE="dnf update -y"
NOBODY_GROUP="nobody"
# Try yum fallback for older systems
if ! command -v dnf &> /dev/null; then
PKG_MGR="yum"
PKG_INSTALL="yum install -y"
fi
;;
amzn)
PKG_MGR="yum"
PKG_INSTALL="yum install -y"
PKG_UPDATE="yum update -y"
NOBODY_GROUP="nobody"
;;
*)
echo -e "${RED}Error: Unsupported distribution: $ID${NC}"
exit 1
;;
esac
else
echo -e "${RED}Error: Cannot detect distribution${NC}"
exit 1
fi
}
# Main installation steps
main() {
echo -e "${GREEN}Starting OpenVPN Prometheus Monitoring Stack Installation${NC}"
check_prerequisites
detect_distro
echo -e "${GREEN}[1/10] Updating system packages${NC}"
$PKG_UPDATE
echo -e "${GREEN}[2/10] Installing dependencies${NC}"
$PKG_INSTALL python3 python3-pip git wget curl tar
echo -e "${GREEN}[3/10] Configuring OpenVPN status logging${NC}"
mkdir -p /var/log/openvpn
chown nobody:$NOBODY_GROUP /var/log/openvpn
chmod 755 /var/log/openvpn
# Add status logging to OpenVPN config if not present
OPENVPN_CONFIG="/etc/openvpn/server.conf"
if [ -f "$OPENVPN_CONFIG" ]; then
if ! grep -q "status.*openvpn-status.log" "$OPENVPN_CONFIG"; then
cat >> "$OPENVPN_CONFIG" << EOF
# OpenVPN status monitoring
status /var/log/openvpn/openvpn-status.log 10
status-version 2
management localhost 7505
EOF
fi
else
echo -e "${YELLOW}Warning: OpenVPN config not found at $OPENVPN_CONFIG${NC}"
fi
echo -e "${GREEN}[4/10] Restarting OpenVPN service${NC}"
systemctl restart "$OPENVPN_SERVICE" || echo -e "${YELLOW}Warning: Failed to restart $OPENVPN_SERVICE${NC}"
echo -e "${GREEN}[5/10] Installing Prometheus${NC}"
cd /tmp
wget -O prometheus.tar.gz "https://github.com/prometheus/prometheus/releases/download/v${PROMETHEUS_VERSION}/prometheus-${PROMETHEUS_VERSION}.linux-amd64.tar.gz"
tar xzf prometheus.tar.gz
mv "prometheus-${PROMETHEUS_VERSION}.linux-amd64" /opt/prometheus
# Create prometheus user
if ! id prometheus &>/dev/null; then
useradd --no-create-home --shell /bin/false prometheus
fi
echo -e "${GREEN}[6/10] Configuring Prometheus directories${NC}"
mkdir -p /etc/prometheus /var/lib/prometheus
chown prometheus:prometheus /etc/prometheus /var/lib/prometheus
chown -R prometheus:prometheus /opt/prometheus
chmod 755 /etc/prometheus /var/lib/prometheus /opt/prometheus
echo -e "${GREEN}[7/10] Creating Prometheus configuration${NC}"
cat > /etc/prometheus/prometheus.yml << 'EOF'
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'openvpn'
static_configs:
- targets: ['localhost:9176']
scrape_interval: 10s
metrics_path: /metrics
EOF
chown prometheus:prometheus /etc/prometheus/prometheus.yml
chmod 644 /etc/prometheus/prometheus.yml
echo -e "${GREEN}[8/10] Creating Prometheus systemd service${NC}"
cat > /etc/systemd/system/prometheus.service << 'EOF'
[Unit]
Description=Prometheus
Wants=network-online.target
After=network-online.target
[Service]
User=prometheus
Group=prometheus
Type=simple
ExecStart=/opt/prometheus/prometheus \
--config.file /etc/prometheus/prometheus.yml \
--storage.tsdb.path /var/lib/prometheus/ \
--web.console.templates=/opt/prometheus/consoles \
--web.console.libraries=/opt/prometheus/console_libraries \
--web.listen-address=0.0.0.0:9090
[Install]
WantedBy=multi-user.target
EOF
echo -e "${GREEN}[9/10] Installing OpenVPN Prometheus exporter${NC}"
cd /opt
git clone https://github.com/kumina/openvpn_exporter.git
cd openvpn_exporter
pip3 install -r requirements.txt
chown -R nobody:$NOBODY_GROUP /opt/openvpn_exporter
chmod -R 755 /opt/openvpn_exporter
# Create OpenVPN exporter systemd service
cat > /etc/systemd/system/openvpn-exporter.service << EOF
[Unit]
Description=OpenVPN Prometheus Exporter
After=network.target
[Service]
Type=simple
User=nobody
Group=$NOBODY_GROUP
ExecStart=/usr/bin/python3 /opt/openvpn_exporter/openvpn_exporter.py \
--openvpn.status-paths /var/log/openvpn/openvpn-status.log \
--web.listen-address 0.0.0.0:9176
Restart=always
RestartSec=15
[Install]
WantedBy=multi-user.target
EOF
echo -e "${GREEN}[10/10] Starting and enabling services${NC}"
systemctl daemon-reload
systemctl enable --now prometheus
systemctl enable --now openvpn-exporter
# Configure firewall if active
if systemctl is-active --quiet firewalld; then
firewall-cmd --permanent --add-port=9090/tcp --add-port=9176/tcp
firewall-cmd --reload
elif systemctl is-active --quiet ufw; then
ufw allow 9090/tcp
ufw allow 9176/tcp
fi
# Verification
echo -e "${GREEN}Verifying installation...${NC}"
sleep 5
if systemctl is-active --quiet prometheus; then
echo -e "${GREEN}✓ Prometheus is running${NC}"
else
echo -e "${RED}✗ Prometheus failed to start${NC}"
fi
if systemctl is-active --quiet openvpn-exporter; then
echo -e "${GREEN}✓ OpenVPN exporter is running${NC}"
else
echo -e "${RED}✗ OpenVPN exporter failed to start${NC}"
fi
if curl -sf http://localhost:9090 > /dev/null; then
echo -e "${GREEN}✓ Prometheus web interface accessible${NC}"
else
echo -e "${YELLOW}⚠ Prometheus web interface not accessible${NC}"
fi
if curl -sf http://localhost:9176/metrics > /dev/null; then
echo -e "${GREEN}✓ OpenVPN metrics endpoint accessible${NC}"
else
echo -e "${YELLOW}⚠ OpenVPN metrics endpoint not accessible${NC}"
fi
echo -e "${GREEN}Installation completed successfully!${NC}"
echo -e "${GREEN}Prometheus: http://$(hostname -I | awk '{print $1}'):9090${NC}"
echo -e "${GREEN}OpenVPN Metrics: http://$(hostname -I | awk '{print $1}'):9176/metrics${NC}"
echo -e "${YELLOW}Note: Install Grafana separately and import OpenVPN dashboard${NC}"
}
main "$@"
Review the script before running. Execute with: bash install.sh