🚀 Executive Summary
TL;DR: Manually checking WireGuard VPN status is inefficient and can lead to unnoticed issues. This tutorial provides a solution by creating a Python script to parse `wg show` output and automatically send formatted status reports to a private Telegram bot, offering at-a-glance visibility into VPN health.
🎯 Key Takeaways
- Telegram bot creation involves using `@BotFather` to obtain an HTTP API token and a utility script (`find_chat_id.py`) to retrieve the personal Chat ID for message delivery.
- The core monitoring script (`wg_monitor.py`) executes the `wg show` command, parses its output using regular expressions to extract peer public keys, latest handshakes, and data transfer statistics.
- Secure credential management is achieved by storing sensitive Bot Token and Chat ID in a separate `config.ini` file, preventing hardcoding within the Python script.
- Automation of status reports is implemented using cron jobs, scheduling the `wg_monitor.py` script to run at specified intervals for consistent monitoring.
- Common implementation pitfalls include `wg show` permission errors (requiring elevated privileges or sudoers configuration) and Python environment discrepancies in cron jobs (requiring absolute paths for executables and system-wide dependency installation).
Self-Hosted VPN Monitoring: WireGuard Status to Telegram Bot
Introduction
Running your own WireGuard VPN server provides excellent privacy and control, but it can often feel like a black box. Are your peers connecting? When was the last successful handshake? How much data has been transferred? Answering these questions manually is tedious and inefficient. Without proactive monitoring, you might not notice a configuration issue or an inactive client until it becomes a problem.
This tutorial solves that problem by creating a simple, powerful monitoring system. We will write a Python script to parse the status of your WireGuard interface and automatically send a neatly formatted report to a private Telegram bot. This gives you at-a-glance visibility into your VPN’s health, delivered directly to your phone or desktop, turning your “black box” into a transparent, manageable service.
Prerequisites
Before we begin, ensure you have the following in place:
- A Linux server with WireGuard installed and running.
- Administrative (root or equivalent) access to the server.
- Python 3 and the
pippackage manager installed. - A Telegram account.
Step-by-Step Guide
We’ll break this process down into four main steps: creating the bot, writing the monitoring script, securing our credentials, and automating the execution.
Step 1: Create a Telegram Bot and Obtain Credentials
First, we need a bot to send messages. Telegram’s “BotFather” makes this incredibly easy.
- Create the Bot: Open Telegram, search for the user
@BotFather, and start a chat. Send the/newbotcommand and follow the prompts to choose a name and username for your bot. - Save Your Bot Token: Once created, BotFather will provide you with an HTTP API token. It will look something like
1234567890:ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789. Treat this token like a password and save it securely. - Find Your Chat ID: The bot needs to know where to send the message. To get your personal Chat ID, send a message to your newly created bot first. Then, you can run the following Python script on any machine with Python installed to retrieve it. Remember to install the required library with
pip install python-telegram-bot.
# find_chat_id.py
# A simple utility to get your Telegram Chat ID.
import asyncio
from telegram import Bot
# IMPORTANT: Replace with your actual bot token
BOT_TOKEN = "YOUR_API_TOKEN_HERE"
async def main():
bot = Bot(token=BOT_TOKEN)
print("Fetching updates...")
try:
updates = await bot.get_updates(timeout=10, limit=1)
if updates:
chat_id = updates[0].message.chat_id
print(f"Success! Your Chat ID is: {chat_id}")
else:
print("No new messages found. Please send a message to your bot and run this script again.")
except Exception as e:
print(f"An error occurred: {e}")
print("Ensure your BOT_TOKEN is correct and you have sent a message to the bot.")
if __name__ == "__main__":
asyncio.run(main())
Run the script using python3 find_chat_id.py. Save the numeric Chat ID it outputs. You will need both the Bot Token and the Chat ID in the next steps.
Step 2: The Python Monitoring Script
Now, let’s create the core script that gathers WireGuard data and sends it to Telegram. This script will execute the wg show command, parse its output, and format a clear, readable status report.
First, install the necessary Python library:
pip install requests
Next, create a file named wg_monitor.py and add the following code. The logic is explained in the comments.
# wg_monitor.py
import subprocess
import re
import requests
import configparser
from datetime import datetime
def get_wireguard_status():
"""Executes 'wg show' and returns its output."""
try:
# The 'wg show' command requires elevated privileges.
# Ensure the user running this script has permission.
result = subprocess.run(
['wg', 'show'],
capture_output=True,
text=True,
check=True
)
return result.stdout
except (subprocess.CalledProcessError, FileNotFoundError) as e:
print(f"Error executing 'wg show': {e}")
return None
def parse_wg_status(output):
"""Parses the raw output from 'wg show' into a structured format."""
peers = []
current_peer = None
for line in output.strip().split('\n'):
# Each peer section starts with 'peer:'
peer_match = re.search(r'peer: (\S+)', line)
if peer_match:
if current_peer:
peers.append(current_peer)
current_peer = {'public_key': peer_match.group(1)}
continue
# Extract other details for the current peer
if current_peer:
handshake_match = re.search(r'latest handshake: (.+)', line)
transfer_match = re.search(r'transfer: (.+ received, .+ sent)', line)
if handshake_match:
current_peer['latest_handshake'] = handshake_match.group(1)
if transfer_match:
current_peer['transfer'] = transfer_match.group(1)
if current_peer:
peers.append(current_peer)
return peers
def format_telegram_message(peers):
"""Formats the parsed peer data into a Telegram-friendly message."""
if not peers:
return "WireGuard Status: No peers found or interface is down."
# Get the server name for a nicer title
hostname = subprocess.run(['hostname'], capture_output=True, text=True).stdout.strip()
# Using HTML for bold and monospace formatting in Telegram
message = f"<b>WireGuard Status Report ({hostname})</b>\n"
message += f"<i>Generated on: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</i>\n\n"
for i, peer in enumerate(peers):
# We use a comment or alias for the peer public key if available
# This requires you to add '# friendly-name' in your wg0.conf
public_key = peer.get('public_key', 'N/A')
handshake = peer.get('latest_handshake', 'N/A')
transfer = peer.get('transfer', 'N/A')
message += f"<b>Peer {i+1}:</b> <code>...{public_key[-8:]}</code>\n"
message += f" 🤝 Handshake: {handshake}\n"
message += f" 📊 Transfer: {transfer}\n\n"
return message
def send_telegram_message(token, chat_id, message):
"""Sends the formatted message to the Telegram Bot API."""
api_url = f"https://api.telegram.org/bot{token}/sendMessage"
payload = {
'chat_id': chat_id,
'text': message,
'parse_mode': 'HTML' # Use HTML for formatting
}
try:
response = requests.post(api_url, data=payload, timeout=10)
response.raise_for_status()
print("Successfully sent message to Telegram.")
except requests.exceptions.RequestException as e:
print(f"Failed to send message: {e}")
def main():
# Read credentials from a configuration file
config = configparser.ConfigParser()
config.read('config.ini')
bot_token = config['telegram']['BotToken']
chat_id = config['telegram']['ChatID']
wg_output = get_wireguard_status()
if wg_output:
peers_data = parse_wg_status(wg_output)
telegram_message = format_telegram_message(peers_data)
send_telegram_message(bot_token, chat_id, telegram_message)
if __name__ == "__main__":
main()
Step 3: Secure Your Credentials
Hardcoding tokens and IDs directly into your script is a security risk. A better practice is to store them in a separate configuration file. Create a file named config.ini in the same directory as your Python script.
# config.ini
[telegram]
BotToken = YOUR_API_TOKEN_HERE
ChatID = YOUR_CHAT_ID_HERE
Replace the placeholders with your actual Bot Token and Chat ID. Our Python script is already designed to read from this file, keeping your sensitive information separate from your code.
Step 4: Automate with Cron
Finally, we’ll use a cron job to run our script automatically on a schedule. This way, you’ll receive status reports without any manual intervention.
Open your cron editor with the appropriate command for your system (e.g., crontab -e).
Add the following line to the file to schedule the script to run every day at 8:00 AM. Adjust the schedule (0 8 * * *) and file path to fit your needs.
# Run the WireGuard monitor script daily at 8 AM
0 8 * * * python3 /home/user/wg_monitor/wg_monitor.py
Note: Make sure to use the absolute path to your Python script. The cron job will execute from your user’s home directory, so relative paths can fail.
Common Pitfalls
-
Permission Errors with `wg` command: The
wg showcommand typically requires elevated privileges to inspect the network interface. If the user running the cron job does not have these permissions, the script will fail. You may need to configure your system to allow the user to run this specific command without a password. Search for how to grant specific command permissions via your system’s sudoers configuration. -
Python Environment and Dependencies: Cron jobs run in a minimal shell environment, which might not have the same PATH as your interactive shell. If the script fails to find the
requestslibrary, it’s because the Python interpreter being used by cron doesn’t know about it. To fix this, you can either use the absolute path to the Python executable within a virtual environment (e.g.,/home/user/venv/bin/python3) in your cron job, or ensure the library is installed for the system’s default Python 3 interpreter.
Conclusion
You have now successfully built an automated monitoring system for your self-hosted WireGuard VPN. This setup provides timely, valuable insights into your VPN’s activity, enhancing both security and reliability. The script is easily extensible; you could add logic to alert on peers with old handshakes, track data usage over time, or integrate it with other dashboarding tools.
By transforming command-line output into actionable notifications, you’ve taken a significant step towards professional-grade management of your personal infrastructure. Happy monitoring!
🤖 Frequently Asked Questions
❓ How can I monitor my WireGuard VPN status automatically and receive alerts?
You can automate WireGuard monitoring by deploying a Python script that executes the `wg show` command, parses its output for peer status (handshakes, transfer data), formats the information, and sends it to a private Telegram bot using the Telegram Bot API. This script is then scheduled to run periodically via a cron job on your Linux server.
❓ How does this automated Telegram bot monitoring compare to manual checks or other monitoring solutions?
This solution significantly enhances monitoring over manual `wg show` checks by providing proactive, automated, and easily digestible reports directly to your Telegram client. Compared to more complex, enterprise-grade monitoring systems, it offers a lightweight, self-hosted, and highly customizable approach, ideal for personal or small-scale VPN deployments without extensive overhead.
❓ What are common implementation pitfalls when setting up WireGuard monitoring with a Telegram bot, and how can they be resolved?
Two common pitfalls are permission errors for the `wg show` command and Python environment issues within cron jobs. To resolve permission errors, ensure the user executing the script has elevated privileges for `wg show` (e.g., via sudoers configuration). For cron’s minimal environment, use absolute paths for the Python executable and script, and ensure necessary Python dependencies like `requests` are installed for the specific Python interpreter used by cron.
Leave a Reply