Skip to content

Instantly share code, notes, and snippets.

@labmonkey
Last active June 9, 2025 16:43
Show Gist options
  • Select an option

  • Save labmonkey/0677f6cc12c94d799356d4d2ddf7a4b5 to your computer and use it in GitHub Desktop.

Select an option

Save labmonkey/0677f6cc12c94d799356d4d2ddf7a4b5 to your computer and use it in GitHub Desktop.
OpenVPN client connect and disconnect notification to Discord (working on AsusWRT)

Discord notification for OpenVPN Client connect and Disconnect + GeoIP lookup

  • simple: easy to understand code, just a text notification
  • advanced: discord embeds with fields + GeoIP country and city lookup
#!/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
#!/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
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