- 
      
- 
        Save zh-if/768a63544f48b0caabc89860133a3abb to your computer and use it in GitHub Desktop. 
Revisions
- 
        brandon1024 revised this gist Mar 24, 2023 . 2 changed files with 1 addition and 1 deletion.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -59,6 +59,6 @@ pQNmjK+YF7/OLTYCon/rUf707gD29SHuKvhxM6f93Eg= Friend ## Building a Grafana Dashboard Once set up, create some visualization for the health and statistics of your Wireguard network in Grafana. You can import the dashboard shown below from the JSON model `wg-grafana-dashboard.json`.  File renamed without changes.
- 
        brandon1024 renamed this gist Mar 24, 2023 . 1 changed file with 0 additions and 0 deletions.There are no files selected for viewingFile renamed without changes.
- 
        brandon1024 renamed this gist Mar 24, 2023 . 1 changed file with 0 additions and 0 deletions.There are no files selected for viewingFile renamed without changes.
- 
        brandon1024 renamed this gist Mar 24, 2023 . 1 changed file with 0 additions and 0 deletions.There are no files selected for viewingFile renamed without changes.
- 
        brandon1024 revised this gist Mar 24, 2023 . 2 changed files with 952 additions and 1 deletion.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -55,4 +55,10 @@ Zo0Z5MClSQZsWlG3hS9RgoE6kHQHWYhGJ3i9DuB1yV4= Home Server fvEBlU5mZGelXse9copyYt/c75H9XfQeVMFGVItJu1Q= Phone wDArzrW4UnZ6Zfp7/zHvGNH0wx71yhEqOXTu6Jgfbgc= Personal Laptop pQNmjK+YF7/OLTYCon/rUf707gD29SHuKvhxM6f93Eg= Friend ``` ## Building a Grafana Dashboard Once set up, create some visualization for the health and statistics of your Wireguard network in Grafana. You can import the dashboard shown below from the JSON model `grafana-dashboard.json`.  This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,945 @@ { "annotations": { "list": [ { "builtIn": 1, "datasource": { "type": "grafana", "uid": "-- Grafana --" }, "enable": true, "hide": true, "iconColor": "rgba(0, 211, 255, 1)", "name": "Annotations & Alerts", "target": { "limit": 100, "matchAny": false, "tags": [], "type": "dashboard" }, "type": "dashboard" } ] }, "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, "id": 5, "links": [], "liveNow": false, "panels": [ { "datasource": { "type": "prometheus", "uid": "s8uwo_x4k" }, "fieldConfig": { "defaults": { "color": { "mode": "fixed" }, "displayName": "Peers", "mappings": [], "noValue": "None", "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 80 } ] } }, "overrides": [] }, "gridPos": { "h": 4, "w": 2, "x": 0, "y": 0 }, "id": 10, "options": { "colorMode": "value", "graphMode": "none", "justifyMode": "auto", "orientation": "auto", "reduceOptions": { "calcs": [ "lastNotNull" ], "fields": "", "values": false }, "textMode": "value_and_name" }, "pluginVersion": "9.4.3", "targets": [ { "datasource": { "type": "prometheus", "uid": "s8uwo_x4k" }, "editorMode": "code", "expr": "count(node_network_wireguard_peer_handshake{job=\"$job\",instance=\"$node\",device=\"$interface\"})", "legendFormat": "__auto", "range": true, "refId": "A" } ], "transparent": true, "type": "stat" }, { "datasource": { "type": "prometheus", "uid": "s8uwo_x4k" }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, "displayName": "Active Peers", "mappings": [], "min": 0, "noValue": "None", "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 80 } ] } }, "overrides": [] }, "gridPos": { "h": 4, "w": 6, "x": 2, "y": 0 }, "id": 11, "options": { "colorMode": "value", "graphMode": "area", "justifyMode": "auto", "orientation": "auto", "reduceOptions": { "calcs": [ "lastNotNull" ], "fields": "", "values": false }, "textMode": "value_and_name" }, "pluginVersion": "9.4.3", "targets": [ { "datasource": { "type": "prometheus", "uid": "s8uwo_x4k" }, "editorMode": "code", "expr": "count((time() - node_network_wireguard_peer_handshake{job=\"$job\",instance=\"$node\",device=\"$interface\"}) <= 180)", "legendFormat": "__auto", "range": true, "refId": "A" } ], "transparent": true, "type": "stat" }, { "datasource": { "type": "prometheus", "uid": "s8uwo_x4k" }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, "custom": { "align": "auto", "cellOptions": { "type": "color-text" }, "filterable": false, "inspect": false }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 180 } ] }, "unit": "dtdurations" }, "overrides": [ { "matcher": { "id": "byName", "options": "Name" }, "properties": [ { "id": "custom.cellOptions", "value": { "type": "auto" } } ] }, { "matcher": { "id": "byName", "options": "Public Key" }, "properties": [ { "id": "custom.cellOptions", "value": { "type": "auto" } }, { "id": "custom.width", "value": 258 } ] }, { "matcher": { "id": "byName", "options": "Allowed IPs" }, "properties": [ { "id": "custom.cellOptions", "value": { "type": "auto" } }, { "id": "custom.width", "value": 142 } ] }, { "matcher": { "id": "byName", "options": "Persistent Keepalive" }, "properties": [ { "id": "custom.cellOptions", "value": { "type": "auto" } }, { "id": "custom.width", "value": 161 } ] } ] }, "gridPos": { "h": 8, "w": 16, "x": 8, "y": 0 }, "id": 4, "options": { "footer": { "countRows": false, "enablePagination": true, "fields": [], "reducer": [ "sum" ], "show": false }, "showHeader": true, "sortBy": [] }, "pluginVersion": "9.4.3", "targets": [ { "datasource": { "type": "prometheus", "uid": "s8uwo_x4k" }, "editorMode": "code", "exemplar": false, "expr": "time() - node_network_wireguard_peer_handshake{job=\"$job\",instance=\"$node\",device=\"$interface\"}", "format": "table", "instant": true, "legendFormat": "__auto", "range": false, "refId": "A" } ], "title": "Active Peers", "transformations": [ { "id": "filterFieldsByName", "options": { "include": { "names": [ "endpoint", "name", "persistent_keepalive", "public_key", "Value" ] } } }, { "id": "organize", "options": { "excludeByName": {}, "indexByName": { "Value": 5, "device": 0, "endpoint": 3, "name": 1, "persistent_keepalive": 4, "public_key": 2 }, "renameByName": { "Value": "Handshake", "device": "Interface", "endpoint": "Allowed IPs", "name": "Name", "persistent_keepalive": "Persistent Keepalive", "public_key": "Public Key" } } }, { "id": "sortBy", "options": { "fields": {}, "sort": [ { "field": "Handshake" } ] } } ], "transparent": true, "type": "table" }, { "datasource": { "type": "prometheus", "uid": "s8uwo_x4k" }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, "displayName": "↑", "mappings": [], "noValue": "None", "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null } ] }, "unit": "decbytes" }, "overrides": [] }, "gridPos": { "h": 4, "w": 4, "x": 0, "y": 4 }, "id": 12, "options": { "colorMode": "value", "graphMode": "area", "justifyMode": "auto", "orientation": "auto", "reduceOptions": { "calcs": [ "lastNotNull" ], "fields": "", "values": false }, "textMode": "value_and_name" }, "pluginVersion": "9.4.3", "targets": [ { "datasource": { "type": "prometheus", "uid": "s8uwo_x4k" }, "editorMode": "code", "expr": "sum(node_network_wireguard_peer_tx{job=\"$job\",instance=\"$node\",device=\"$interface\"})", "legendFormat": "__auto", "range": true, "refId": "A" } ], "transparent": true, "type": "stat" }, { "datasource": { "type": "prometheus", "uid": "s8uwo_x4k" }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, "displayName": "↓", "mappings": [], "noValue": "None", "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null } ] }, "unit": "decbytes" }, "overrides": [] }, "gridPos": { "h": 4, "w": 4, "x": 4, "y": 4 }, "id": 13, "options": { "colorMode": "value", "graphMode": "area", "justifyMode": "auto", "orientation": "auto", "reduceOptions": { "calcs": [ "lastNotNull" ], "fields": "", "values": false }, "textMode": "value_and_name" }, "pluginVersion": "9.4.3", "targets": [ { "datasource": { "type": "prometheus", "uid": "s8uwo_x4k" }, "editorMode": "code", "expr": "sum(node_network_wireguard_peer_rx{job=\"$job\",instance=\"$node\",device=\"$interface\"})", "legendFormat": "__auto", "range": true, "refId": "A" } ], "transparent": true, "type": "stat" }, { "datasource": { "type": "prometheus", "uid": "s8uwo_x4k" }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", "fillOpacity": 0, "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, "viz": false }, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, "scaleDistribution": { "type": "linear" }, "showPoints": "auto", "spanNulls": false, "stacking": { "group": "A", "mode": "none" }, "thresholdsStyle": { "mode": "off" } }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 80 } ] }, "unit": "bytes" }, "overrides": [ { "matcher": { "id": "byFrameRefID", "options": "B" }, "properties": [ { "id": "custom.transform", "value": "negative-Y" } ] } ] }, "gridPos": { "h": 11, "w": 24, "x": 0, "y": 8 }, "id": 6, "options": { "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true }, "tooltip": { "mode": "single", "sort": "none" } }, "targets": [ { "datasource": { "type": "prometheus", "uid": "s8uwo_x4k" }, "editorMode": "code", "exemplar": false, "expr": "label_replace(sum(irate(node_network_wireguard_peer_rx{job=\"$job\",instance=\"$node\",device=\"$interface\"}[$__rate_interval])), \"device\", \"$interface\", \"device\", \"\")", "format": "time_series", "instant": false, "legendFormat": "recv {{device}}", "range": true, "refId": "A" }, { "datasource": { "type": "prometheus", "uid": "s8uwo_x4k" }, "editorMode": "code", "exemplar": false, "expr": "label_replace(sum(irate(node_network_wireguard_peer_tx{job=\"$job\",instance=\"$node\",device=\"$interface\"}[$__rate_interval])), \"device\", \"$interface\", \"device\", \"\")", "format": "time_series", "hide": false, "instant": false, "legendFormat": "trans {{device}} ", "range": true, "refId": "B" } ], "title": "Wireguard Traffic", "transformations": [], "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "s8uwo_x4k" }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", "fillOpacity": 0, "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, "viz": false }, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, "scaleDistribution": { "type": "linear" }, "showPoints": "auto", "spanNulls": false, "stacking": { "group": "A", "mode": "none" }, "thresholdsStyle": { "mode": "off" } }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 80 } ] }, "unit": "bytes" }, "overrides": [] }, "gridPos": { "h": 13, "w": 12, "x": 0, "y": 19 }, "id": 7, "options": { "legend": { "calcs": [ "lastNotNull" ], "displayMode": "table", "placement": "bottom", "showLegend": true, "sortBy": "Last *", "sortDesc": true }, "tooltip": { "mode": "single", "sort": "none" } }, "targets": [ { "datasource": { "type": "prometheus", "uid": "s8uwo_x4k" }, "editorMode": "code", "exemplar": false, "expr": "node_network_wireguard_peer_rx{job=\"$job\",instance=\"$node\",device=\"$interface\"}", "format": "time_series", "instant": false, "legendFormat": "__auto", "range": true, "refId": "A" } ], "title": "Peer Rx", "transformations": [ { "id": "labelsToFields", "options": { "keepLabels": [ "endpoint", "name", "persistent_keepalive", "public_key" ], "mode": "columns", "valueLabel": "name" } } ], "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "s8uwo_x4k" }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", "fillOpacity": 0, "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, "viz": false }, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, "scaleDistribution": { "type": "linear" }, "showPoints": "auto", "spanNulls": false, "stacking": { "group": "A", "mode": "none" }, "thresholdsStyle": { "mode": "off" } }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 80 } ] }, "unit": "bytes" }, "overrides": [] }, "gridPos": { "h": 13, "w": 12, "x": 12, "y": 19 }, "id": 8, "options": { "legend": { "calcs": [ "lastNotNull" ], "displayMode": "table", "placement": "bottom", "showLegend": true, "sortBy": "Last *", "sortDesc": true }, "tooltip": { "mode": "single", "sort": "none" } }, "targets": [ { "datasource": { "type": "prometheus", "uid": "s8uwo_x4k" }, "editorMode": "code", "exemplar": false, "expr": "node_network_wireguard_peer_tx{job=\"$job\",instance=\"$node\",device=\"$interface\"}", "format": "time_series", "instant": false, "legendFormat": "__auto", "range": true, "refId": "A" } ], "title": "Peer Tx", "transformations": [ { "id": "labelsToFields", "options": { "keepLabels": [ "endpoint", "name", "persistent_keepalive", "public_key" ], "mode": "columns", "valueLabel": "name" } } ], "type": "timeseries" } ], "refresh": "10s", "revision": 1, "schemaVersion": 38, "style": "dark", "tags": [], "templating": { "list": [ { "current": { "selected": false, "text": "node", "value": "node" }, "datasource": { "type": "prometheus", "uid": "s8uwo_x4k" }, "definition": "label_values(node_uname_info, job)", "hide": 0, "includeAll": false, "label": "Job", "multi": false, "name": "job", "options": [], "query": { "query": "label_values(node_uname_info, job)", "refId": "StandardVariableQuery" }, "refresh": 1, "regex": "", "skipUrlSync": false, "sort": 0, "type": "query" }, { "current": { "selected": false, "text": "n1.opti.lan:9100", "value": "n1.opti.lan:9100" }, "datasource": { "type": "prometheus", "uid": "s8uwo_x4k" }, "definition": "label_values(node_uname_info{job=\"$job\"}, instance)", "hide": 0, "includeAll": false, "label": "Host", "multi": false, "name": "node", "options": [], "query": { "query": "label_values(node_uname_info{job=\"$job\"}, instance)", "refId": "StandardVariableQuery" }, "refresh": 1, "regex": "", "skipUrlSync": false, "sort": 0, "type": "query" }, { "current": { "selected": false, "text": "wg0", "value": "wg0" }, "datasource": { "type": "prometheus", "uid": "s8uwo_x4k" }, "definition": "label_values(node_network_wireguard_interface{job=\"$job\",instance=\"$node\"}, device)", "hide": 0, "includeAll": false, "label": "Interface", "multi": false, "name": "interface", "options": [], "query": { "query": "label_values(node_network_wireguard_interface{job=\"$job\",instance=\"$node\"}, device)", "refId": "StandardVariableQuery" }, "refresh": 1, "regex": "", "skipUrlSync": false, "sort": 0, "type": "query" } ] }, "time": { "from": "now-1h", "to": "now" }, "timepicker": {}, "timezone": "", "title": "Wireguard Network", "uid": "DnjWvia4z", "version": 34, "weekStart": "" } 
- 
        brandon1024 revised this gist Mar 24, 2023 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -5,7 +5,7 @@ This file can be read by the [node_exporter textfile collector](https://github.c You might be asking, why does this exist? Why not [MindFlavor/prometheus_wireguard_exporter](https://github.com/MindFlavor/prometheus_wireguard_exporter)? The reality is that a full-fledged webserver written in Rust to expose wireguard metrics is a bit overkill. I've accomplished the same thing in ~100 lines of (well documented) Awk. It's dead simple, and a no brainer if you're already using node-exporter. For those conscious about security, you'll be happy to know the script itself does't run any wireguard commands; it doesn't even need to be run as root. It accepts a wg dump from stdin, and that's it. The metrics exposition is completely isolated from the wireguard configuration, unlike [MindFlavor/prometheus_wireguard_exporter](https://github.com/MindFlavor/prometheus_wireguard_exporter). No need to deal with docker containers attached to the host network, which is annoying when you're running mostly rootless containers. ## Simplest Usage 
- 
        brandon1024 revised this gist Mar 8, 2023 . 5 changed files with 88 additions and 87 deletions.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -3,11 +3,7 @@ Here's a simple set of scripts that allow you to export wireguard tunnel statistics to a file in Prometheus text format. This file can be read by the [node_exporter textfile collector](https://github.com/prometheus/node_exporter#textfile-collector), for example. You might be asking, why does this exist? Why not [MindFlavor/prometheus_wireguard_exporter](https://github.com/MindFlavor/prometheus_wireguard_exporter)? The reality is that a full-fledged webserver written in Rust to expose wireguard metrics is a bit overkill. I've accomplished the same thing in ~100 lines of (well documented) Awk. It's dead simple, and a no brainer if you're already using node-exporter. For those conscious about security, this is bit easier to deal with too. The script itself does't run any wireguard commands; it doesn't even need to be run as root. It accepts a wg dump from stdin, and that's it. The metrics exposition is completely isolated from the wireguard configuration, unlike [MindFlavor/prometheus_wireguard_exporter](https://github.com/MindFlavor/prometheus_wireguard_exporter). No need to deal with docker containers attached to the host network, which is annoying when you're running mostly rootless containers. @@ -48,25 +44,15 @@ If you want to use this script to expose wireguard metrics to Prometheus: # systemctl start prometheus-collect-wg.timer ``` ## Mapping Public Keys to Human Friendly Names Public keys aren't all that useful for us mortals. Mapping these keys to human-friendly names is easy (and no it does not involve [vanity keys](https://github.com/warner/wireguard-vanity-address)). Simply create a key map file and provide the path to the file as an environment variable. The key map file is a tab-separated file where each line in the file maps a public key to it's human-friendly name. ``` Zo0Z5MClSQZsWlG3hS9RgoE6kHQHWYhGJ3i9DuB1yV4= Home Server fvEBlU5mZGelXse9copyYt/c75H9XfQeVMFGVItJu1Q= Phone wDArzrW4UnZ6Zfp7/zHvGNH0wx71yhEqOXTu6Jgfbgc= Personal Laptop pQNmjK+YF7/OLTYCon/rUf707gD29SHuKvhxM6f93Eg= Friend ``` This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -3,7 +3,10 @@ Description=Export Wireguard metrics to a file for consumption by node exporter [Service] Type=oneshot Environment="WG_KEY_ID_MAP_PATH=/etc/wireguard/peer-key-ids.conf" Environment="PROMETHEUS_TEXTFILE_DIR=/var/run/prometheus" ExecStartPre=/usr/bin/mkdir -p $PROMETHEUS_TEXTFILE_DIR ExecStart=wg-dump-collector.sh [Install] WantedBy=default.target This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -6,4 +6,4 @@ OnBootSec=30 OnUnitActiveSec=15 [Install] WantedBy=timers.target This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,12 +1,10 @@ #!/bin/sh set -e TMP=$$ wg show all dump | wg-dump.awk >$PROMETHEUS_TEXTFILE_DIR/wireguard.prom.$TMP mv $PROMETHEUS_TEXTFILE_DIR/wireguard.prom.$TMP $PROMETHEUS_TEXTFILE_DIR/wireguard.prom rm -f $TMP This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,94 +1,108 @@ #!/usr/bin/awk -f # # wg-dump - pick apart wireguard tunnel information and print in prometheus # line format # # Accepts input from `wg show all dump` and transforms into metrics in # prometheus line format to stdout. Human-friendly names can be assigned to peers # by providing a key map file. # # # Key Map File Format & Configuration # # To configure a key map file, set the WG_KEY_ID_MAP_PATH environment variable with # the path to the file. The file must be tab-separated, the first field being # the public key and the second field being an arbitrary name for the key. # # Usage: # $ wg show all dump | wg-dump.awk # $ WG_KEY_ID_MAP_PATH=/etc/wireguard/peer-key-ids.conf wg show all dump | wg-dump.awk # read wireguard interface information BEGIN { wg_key_id_map_file = ENVIRON["WG_KEY_ID_MAP_PATH"] # if a key id map is configured, use it to provide human-friendly names for keys if (wg_key_id_map_file) { FS = "\t" while ((getline < wg_key_id_map_file) > 0) { wg_key_id_map[$1] = $2 } close(wg_key_id_map_file) } FS = " " ERR = 0 } # Lookup the human-friendly name for a key, returning the original key # if no name exists. function public_key_to_name(key) { if (key in wg_key_id_map) { return wg_key_id_map[key] } return key } # Create metrics for an interface. function interface(dev, pubkey, port, fwmark) { name = public_key_to_name(pubkey) labels = "device=\"" dev "\",public_key=\"" pubkey "\",port=\"" port "\",fwmark=\"" fwmark "\",name=\"" name "\"" wireguard_iface["node_network_wireguard_interface{" labels "}"] = "1.0" } # Register metrics for a peer. function peer(dev, pubkey, pre_shared_key, endpoint, allowed_ips, last_handshake, transfer_rx, transfer_tx, persistent_keepalive) { name = public_key_to_name(pubkey) labels = "device=\"" dev "\",public_key=\"" pubkey "\",endpoint=\"" allowed_ips "\",persistent_keepalive=\"" persistent_keepalive "\",name=\"" name "\"" wireguard_peer_handshake["node_network_wireguard_peer_handshake{" labels "}"] = last_handshake wireguard_peer_tx["node_network_wireguard_peer_tx{" labels "}"] = transfer_tx wireguard_peer_rx["node_network_wireguard_peer_rx{" labels "}"] = transfer_rx } # read wireguard peer information { if (NF == 5) { # update metrics for interface interface($1, $3, $4, $5) } else if (NF == 9) { # update metrics for peer peer($1, $2, $3, $4, $5, $6, $7, $8, $9) } else { print "panic: unexpected number of fields in input; expected 5 or 9, was " NF ERR = 1 exit } } # write Prometheus-style metrics to stdout END { if (ERR) exit 1 print "# HELP node_network_wireguard_interface Wireguard network interface information." print "# TYPE node_network_wireguard_interface gauge" for (metric in wireguard_iface) { print metric " " wireguard_iface[metric] } print "# HELP node_network_wireguard_peer_handshake Latest handshake for a particular Wireguard peer." print "# TYPE node_network_wireguard_peer_handshake gauge" for (metric in wireguard_peer_handshake) { print metric " " wireguard_peer_handshake[metric] } print "# HELP node_network_wireguard_peer_tx Transmit statistics for a particular Wireguard peer." print "# TYPE node_network_wireguard_peer_tx counter" for (metric in wireguard_peer_tx) { print metric " " wireguard_peer_tx[metric] } print "# HELP node_network_wireguard_peer_rx Receive statistics for a particular Wireguard peer." print "# TYPE node_network_wireguard_peer_rx counter" for (metric in wireguard_peer_rx) { print metric " " wireguard_peer_rx[metric] } } 
- 
        brandon1024 revised this gist Feb 26, 2023 . 1 changed file with 4 additions and 0 deletions.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -7,6 +7,10 @@ The script also supports writing individual statistics to a set of files in a pa handy if you're looking to pick apart wireguard tunnel statistics but don't fancy parsing `wg show all dump` yourself. More on this later. You might be asking, why does this exist? Why not [MindFlavor/prometheus_wireguard_exporter](https://github.com/MindFlavor/prometheus_wireguard_exporter)? The reality is that a full-fledged webserver written in Rust to expose wireguard metrics is a bit overkill. I've accomplished the same thing in less than 100 lines of Awk. It's dead simple. For those conscious about security, this is bit easier to deal with too. The script itself does't run any wireguard commands; it doesn't even need to be run as root. It accepts a wg dump from stdin, and that's it. The metrics exposition is completely isolated from the wireguard configuration, unlike [MindFlavor/prometheus_wireguard_exporter](https://github.com/MindFlavor/prometheus_wireguard_exporter). No need to deal with docker containers attached to the host network, which is annoying when you're running mostly rootless containers. ## Simplest Usage If you want to dump prometheus metrics to stdout, try this: 
- 
        brandon1024 created this gist Feb 26, 2023 .There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,68 @@ # A Simple Solution for Wireguard Interface and Peer Metrics Exposition to Prometheus Here's a simple set of scripts that allow you to export wireguard tunnel statistics to a file in Prometheus text format. This file can be read by the [node_exporter textfile collector](https://github.com/prometheus/node_exporter#textfile-collector), for example. The script also supports writing individual statistics to a set of files in a particular directory. This can be handy if you're looking to pick apart wireguard tunnel statistics but don't fancy parsing `wg show all dump` yourself. More on this later. ## Simplest Usage If you want to dump prometheus metrics to stdout, try this: ``` # wg show all dump | wg-dump.awk ``` You'll get something like this: ``` # HELP node_network_wireguard_interface Wireguard network interface information. # TYPE node_network_wireguard_interface gauge node_network_wireguard_interface{device="wg0",public_key="wDArzrW4UnZ6Zfp7/zHvGNH0wx71yhEqOXTu6Jgfbgc=",port="51820",fwmark="off"} 1.0 # HELP node_network_wireguard_peer_handshake Latest handshake for a particular Wireguard peer. # TYPE node_network_wireguard_peer_handshake gauge node_network_wireguard_peer_handshake{device="wg0",public_key="Hav2lvmaicPSly4I25oEHcv8o4ycFNIzriADheeSFjY=",endpoint="192.168.3.8/32",persistent_keepalive="off"} 1677452335 node_network_wireguard_peer_handshake{device="wg0",public_key="ypLMnc92ZUDNMSuEUtW0Nh5VWFooxXXWYcaZx8zLU2c=",endpoint="192.168.3.14/32",persistent_keepalive="off"} 1677208600 node_network_wireguard_peer_handshake{device="wg0",public_key="JAJ264l63wILq02WmcWDwFuLAUPhI8XTweRc/Wgxw2M=",endpoint="192.168.3.5/32",persistent_keepalive="off"} 1677452428 ... ``` ## Exposing Metrics to Prometheus If you want to use this script to expose wireguard metrics to Prometheus: - enable the prometheus textfile collector (e.g. `--collector.textfile.directory=/var/run/prometheus`) - create a systemd timer or cron that runs the script on a interval ``` # cp prometheus-collect-wg.timer /etc/systemd/system/ # cp prometheus-collect-wg.service /etc/systemd/system/ # systemctl enable prometheus-collect-wg.timer # systemctl enable prometheus-collect-wg.service # systemctl start prometheus-collect-wg.timer ``` ## Reading Wireguard Tunnel Statistics If you set the `WG_DUMP_PATH` environment variable, `wg-dump.awk` will write each metric to a file with a deterministic name. ``` # export WG_DUMP_PATH=/var/run/wireguard/ # mkdir -p $WG_DUMP_PATH # wg show all dump | wg-dump.awk # ls $WG_DUMP_PATH wg0.interface.fwmark wg0.peer.38a040a78e8b723c43ada8b55d13542d.allowed_ips wg0.peer.5029b1a7ffe9ffcc7f783743106e3041.persistent_keepalive wg0.peer.91e923da80f9eb48773436be45184cd4.transfer_rx wg0.interface.listen_port wg0.peer.38a040a78e8b723c43ada8b55d13542d.endpoint wg0.peer.5029b1a7ffe9ffcc7f783743106e3041.pre_shared_key wg0.peer.91e923da80f9eb48773436be45184cd4.transfer_tx wg0.interface.public_key wg0.peer.38a040a78e8b723c43ada8b55d13542d.latest_handshake wg0.peer.5029b1a7ffe9ffcc7f783743106e3041.public_key wg0.peer.b072fc5cda6ed8033001db938c707071.allowed_ips wg0.peer.0ffebdcc608dbe8be125fbf2f31a3317.allowed_ips wg0.peer.38a040a78e8b723c43ada8b55d13542d.persistent_keepalive wg0.peer.5029b1a7ffe9ffcc7f783743106e3041.transfer_rx wg0.peer.b072fc5cda6ed8033001db938c707071.endpoint wg0.peer.0ffebdcc608dbe8be125fbf2f31a3317.endpoint wg0.peer.38a040a78e8b723c43ada8b55d13542d.pre_shared_key wg0.peer.5029b1a7ffe9ffcc7f783743106e3041.transfer_tx wg0.peer.b072fc5cda6ed8033001db938c707071.latest_handshake wg0.peer.0ffebdcc608dbe8be125fbf2f31a3317.latest_handshake wg0.peer.38a040a78e8b723c43ada8b55d13542d.public_key wg0.peer.64bb269ee450cd04d0971deb8eb0edff.allowed_ips wg0.peer.b072fc5cda6ed8033001db938c707071.persistent_keepalive ... ``` In the example above, `wg0` is the interface name. Files prefixed with `wg0.interface` are statistics for the interface itself (listen port, public key, etc.). Files prefixed with `wg0.peer` are statistics for each peer. The hash (e.g. `0ffebdcc608dbe8be125fbf2f31a3317`) is the MD5 hash of the peer's public key. This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,9 @@ [Unit] Description=Export Wireguard metrics to a file for consumption by node exporter textfile collector. [Service] Type=oneshot ExecStart=%h/wg-dump-collector.sh [Install] WantedBy=default.target This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,9 @@ [Unit] Description=Export Wireguard metrics to a file for consumption by node exporter textfile collector. [Timer] OnBootSec=30 OnUnitActiveSec=15 [Install] WantedBy=timers.target This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,12 @@ #!/bin/sh # # wg-dump-collector.sh - write prometheus metrics to a textfile directory # # This simple script writes the output from the awk script to the textfile # collector directory, so that it can be picked up by the node exporter. # This script is inteded to be run by a cron or systemd timer. set -e wg show all dump | /root/wg-dump.awk >/var/run/prometheus/wireguard.prom.$$ mv /var/run/prometheus/wireguard.prom.$$ /var/run/prometheus/wireguard.prom This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,94 @@ #!/usr/bin/awk -f # # wg-dump - pick apart wireguard tunnel information # # Accepts input from `wg show all dump` and transform into metrics in prometheus format. # If the WG_DUMP_PATH is set, write metrics to disk at that path. # # Usage: # $ wg show all dump | wg-dump # $ WG_DUMP_PATH=/var/run/wireguard/ wg show all dump | wg-dump # Read wireguard interface information. BEGIN { out_dir = ENVIRON["WG_DUMP_PATH"] getline device_name = $1 public_key = $3 listen_port = $4 fwmark = $5 wireguard_iface["node_network_wireguard_interface{device=\"" device_name "\",public_key=\"" public_key "\",port=\"" listen_port "\",fwmark=\"" fwmark "\"}"] = "1.0" if ( length(out_dir) != 0 ) { print public_key > out_dir device_name ".interface.public_key" print listen_port > out_dir device_name ".interface.listen_port" print fwmark > out_dir device_name ".interface.fwmark" } } function compute_md5( data ) { compute_hash = "echo '" data "' | md5sum" compute_hash | getline return $1 } # Read wireguard peer information. { device_name = $1 public_key = $2 pre_shared_key = $3 endpoint = $4 allowed_ips = $5 latest_handshake = $6 transfer_rx = $7 transfer_tx = $8 persistent_keepalive = $9 hash = compute_md5(public_key) if ( length(out_dir) != 0 ) { print public_key > out_dir device_name ".peer." hash ".public_key" print pre_shared_key > out_dir device_name ".peer." hash ".pre_shared_key" print endpoint > out_dir device_name ".peer." hash ".endpoint" print allowed_ips > out_dir device_name ".peer." hash ".allowed_ips" print latest_handshake > out_dir device_name ".peer." hash ".latest_handshake" print transfer_rx > out_dir device_name ".peer." hash ".transfer_rx" print transfer_tx > out_dir device_name ".peer." hash ".transfer_tx" print persistent_keepalive > out_dir device_name ".peer." hash ".persistent_keepalive" } wireguard_peer_handshake["node_network_wireguard_peer_handshake{device=\"" device_name "\",public_key=\"" public_key "\",endpoint=\"" allowed_ips "\",persistent_keepalive=\"" persistent_keepalive "\"}"] = latest_handshake wireguard_peer_tx["node_network_wireguard_peer_tx{device=\"" device_name "\",public_key=\"" public_key "\",endpoint=\"" allowed_ips "\",persistent_keepalive=\"" persistent_keepalive "\"}"] = transfer_tx wireguard_peer_rx["node_network_wireguard_peer_rx{device=\"" device_name "\",public_key=\"" public_key "\",endpoint=\"" allowed_ips "\",persistent_keepalive=\"" persistent_keepalive "\"}"] = transfer_rx } END { # Write Prometheus-style metrics to stdout. print "# HELP node_network_wireguard_interface Wireguard network interface information." print "# TYPE node_network_wireguard_interface gauge" for ( metric in wireguard_iface ) { print metric " " wireguard_iface[metric] } print "# HELP node_network_wireguard_peer_handshake Latest handshake for a particular Wireguard peer." print "# TYPE node_network_wireguard_peer_handshake gauge" for ( metric in wireguard_peer_handshake ) { print metric " " wireguard_peer_handshake[metric] } print "# HELP node_network_wireguard_peer_tx Transmit statistics for a particular Wireguard peer." print "# TYPE node_network_wireguard_peer_tx counter" for ( metric in wireguard_peer_tx ) { print metric " " wireguard_peer_tx[metric] } print "# HELP node_network_wireguard_peer_rx Transmit statistics for a particular Wireguard peer." print "# TYPE node_network_wireguard_peer_rx counter" for ( metric in wireguard_peer_rx ) { print metric " " wireguard_peer_rx[metric] } }