- simple: easy to understand code, just a text notification
- advanced: discord embeds with fields + GeoIP country and city lookup
Last active
June 9, 2025 16:43
-
-
Save labmonkey/0677f6cc12c94d799356d4d2ddf7a4b5 to your computer and use it in GitHub Desktop.
OpenVPN client connect and disconnect notification to Discord (working on AsusWRT)
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 characters
| #!/bin/sh | |
| # Note: In AsusWRT you cannot use bash but just sh | |
| # --- Configuration --- | |
| # Add your Discord Webhook URL here | |
| discord_url="https://discord.com/api/webhooks/your-webhook" | |
| # Add your ipify API key here | |
| api_key="abc123" | |
| # Server name for the notification | |
| server=$(hostname) | |
| server_name="Unknown" | |
| # Blacklisted users (space-separated) | |
| # In case you have some client that you don't want to see notifications of then you can disable it for those users here | |
| # blacklist="item1 item2 item3" | |
| blacklist="baduser " | |
| # Custom avatar URL for the webhook | |
| # Default is OpenVPN logo | |
| avatar_url="https://avatars.githubusercontent.com/u/1569141?s=200&v=4" | |
| # --- Script variables. Set by asuswrt but can override for debugging --- | |
| # script_type="client-connect" | |
| # common_name="user" | |
| # trusted_ip="8.8.8.8" | |
| # --- Functions --- | |
| # Translate server names into nice names | |
| case "$server" in | |
| "home") | |
| server_name="Home" | |
| ;; | |
| "office") | |
| server_name="Office" | |
| ;; | |
| esac | |
| # Function to get city and country from IP using ipify.org | |
| get_location() { | |
| echo "Fetching location for IP: $1" >&2 | |
| local ip=$1 | |
| local ipify_api=$(curl -s "https://geo.ipify.org/api/v2/country,city?apiKey=$api_key&ipAddress=$ip") | |
| city=$(echo "$ipify_api" | jq -r '.location.city // empty') | |
| country=$(echo "$ipify_api" | jq -r '.location.country // empty') | |
| echo "$city,$country" | |
| } | |
| # Function to generate the JSON payload for Discord | |
| generate_post_data() { | |
| echo "Generating JSON..." >&2 | |
| for item in $blacklist; do | |
| if [ "$item" = "$common_name" ]; then | |
| echo "User '$common_name' is in the blacklist. Aborting." >&2 | |
| return 1 | |
| fi | |
| done | |
| # Get location info for client IP | |
| location=$(get_location "$trusted_ip") | |
| city=$(echo "$location" | cut -d',' -f1) | |
| country=$(echo "$location" | cut -d',' -f2) | |
| if [ "$script_type" = "client-connect" ]; then | |
| title="User Connected" | |
| color=65280 # Green | |
| elif [ "$script_type" = "client-disconnect" ]; then | |
| title="User Disconnected" | |
| color=16711680 # Red | |
| fi | |
| # Construct the JSON payload with embeds | |
| cat <<EOF | |
| { | |
| "username": "VPN", | |
| "avatar_url": "$avatar_url", | |
| "embeds": [{ | |
| "title": "$server : $title", | |
| "description": "$description", | |
| "color": $color, | |
| "fields": [ | |
| { | |
| "name": "User", | |
| "value": "${common_name:-Unknown}", | |
| "inline": true | |
| }, | |
| { | |
| "name": "IP Address", | |
| "value": "$trusted_ip", | |
| "inline": true | |
| }, | |
| { | |
| "name": "", | |
| "value": "", | |
| "inline": true | |
| }, | |
| { | |
| "name": "City", | |
| "value": "${city:-Unknown}", | |
| "inline": true | |
| }, | |
| { | |
| "name": "Country", | |
| "value": "${country:-Unknown}", | |
| "inline": true | |
| } | |
| ] | |
| }] | |
| } | |
| EOF | |
| } | |
| # --- Main execution --- | |
| # Generate JSON data | |
| data=$(generate_post_data) | |
| if [ $? -ne 0 ]; then | |
| echo "Could not generate data. Exiting." >&2 | |
| exit 1 | |
| fi | |
| # Send notification to Discord Webhook | |
| echo "Sending notification to Discord..." | |
| response=$(curl -s -o /dev/null -w "%{http_code}" -H "Content-Type: application/json" -X POST -d "$data" "$discord_url") | |
| if [ "$response" -ge 200 ] && [ "$response" -lt 300 ]; then | |
| echo "Notification sent successfully." | |
| else | |
| echo "Failed to send notification. HTTP status code: $response" >&2 | |
| echo "Response data: $data" >&2 | |
| fi |
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 characters
| #!/bin/sh | |
| # Note: In AsusWRT you cannot use bash but just sh | |
| discord_url="https://discord.com/api/webhooks/your-webhook" | |
| # Manually set variables for testing | |
| # script_type="client-connect" | |
| # common_name="someuser" | |
| # space seperated list as string | |
| # In case you have some client that you don't want to see notifications of then you can disable it for this user here | |
| # blacklist="item1 item2 item3" | |
| blacklist="baduser" | |
| generate_post_data() { | |
| for item in $blacklist; do | |
| if [ "$item" = "$common_name" ]; then | |
| echo "User '$common_name' is in the blacklist. Skipping notification." >&2 | |
| return 0 | |
| fi | |
| done | |
| if [ "$script_type" = "client-connect" ]; then | |
| echo "{\"content\": \"User $common_name connected with IP $trusted_ip\"}" | |
| elif [ "$script_type" = "client-disconnect" ]; then | |
| echo "{\"content\": \"User $common_name disconnected with IP $trusted_ip\"}" | |
| fi | |
| } | |
| # Generate JSON data | |
| data=$(generate_post_data) | |
| if [ -z "$data" ]; then | |
| echo "No data to send. Exiting." >&2 | |
| exit 1 | |
| fi | |
| # Send notification to Discord Webhook | |
| echo "Sending notification to Discord..." | |
| response=$(curl -s -o /dev/null -w "%{http_code}" -H "Content-Type: application/json" -X POST -d "$data" "$discord_url") | |
| if [ "$response" -eq 204 ]; then | |
| echo "Notification sent successfully." | |
| else | |
| echo "Failed to send notification. HTTP status code: $response" >&2 | |
| fi |
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 characters
| status /var/log/openvpn-status.log # in case you want a simple way to view connected clients | |
| status-version 1 | |
| script-security 2 | |
| client-connect /jffs/scripts/client-connect.sh # I use same script for both | |
| client-disconnect /jffs/scripts/client-connect.sh | |
| username-as-common-name # In some systems the $common_name variable is just 'user', this fixes it |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment