-
fazi13 joined the community
-
[Plugin] CA Application Auto Update
install the "User Scripts" plugin change the VPN_CONTAINER variable to match the name of yours change the CONTAINERS variable to match the name(s) of the containers (separated by a space) connected to GLUETUN_VPN. this script checks if your containers can reach google.com cloudflare.com or amazon.com if they cannot, they get restarted. it also by default sends you an Unraid notification #!/bin/bash # VPN Container Watchdog Script (Multi-Site Check with Discord Notifications) # Designed for Unraid to monitor containers running through a VPN (e.g., Gluetun) # ----------------------------------------------------------------------------- # CONFIGURATION # ----------------------------------------------------------------------------- # The name of your VPN provider container VPN_CONTAINER="gluetun-vpn" # List of dependent containers to check (separated by spaces) CONTAINERS="prowlarr sonarr radarr" # List of sites to check for connectivity (Google, Cloudflare, Amazon/AWS) TEST_URLS=("https://google.com" "https://cloudflare.com" "https://amazon.com") # How long to wait for recovery in total (900s = 15m) MAX_WAIT_SECONDS=900 # How often to check for recovery status POLL_INTERVAL_SECONDS=30 # Path for the lock file to prevent concurrent runs LOCKFILE="/tmp/vpn_watchdog.lock" # ----------------------------------------------------------------------------- # FUNCTIONS # ----------------------------------------------------------------------------- # Send to Unraid's notification system (which forwards to Discord) send_notification() { local SUBJECT="$1" local MESSAGE="$2" local IMPORTANCE="${3:-normal}" # Log to the User Scripts log echo "$(date): [$IMPORTANCE] $SUBJECT: $MESSAGE" if [ -f /usr/local/emhttp/webGui/scripts/notify ]; then /usr/local/emhttp/webGui/scripts/notify -e "VPN Containers Watchdog" -s "$SUBJECT" -d "$MESSAGE" -i "$IMPORTANCE" fi } # Check if a specific container is running is_container_running() { [ "$(docker inspect -f '{{.State.Running}}' "$1" 2>/dev/null)" == "true" ] } # Test internet connectivity via curl inside a specified container check_connectivity() { local CONTAINER="$1" # If container isn't running, it's definitely not connected if ! is_container_running "$CONTAINER"; then return 1 fi for URL in "${TEST_URLS[@]}"; do if docker exec "$CONTAINER" curl -sf --head "$URL" --connect-timeout 5 > /dev/null; then return 0 # Success fi done return 1 # Failure } # Poll until all specified containers are running AND have internet connectivity check_container_up() { local TARGET_CONTAINERS=("$@") local WAIT_TIME=0 echo "$(date): [INFO] Polling for connectivity: ${TARGET_CONTAINERS[*]} (Max ${MAX_WAIT_SECONDS}s)" while [ $WAIT_TIME -lt $MAX_WAIT_SECONDS ]; do local STILL_OFFLINE=0 for CONTAINER in "${TARGET_CONTAINERS[@]}"; do if ! check_connectivity "$CONTAINER"; then STILL_OFFLINE=$((STILL_OFFLINE + 1)) fi done if [ $STILL_OFFLINE -eq 0 ]; then echo "$(date): [INFO] All polled containers are ONLINE and RUNNING." return 0 fi echo "$(date): [INFO] Still waiting for recovery ($STILL_OFFLINE containers remaining)... ($WAIT_TIME/${MAX_WAIT_SECONDS}s)" sleep $POLL_INTERVAL_SECONDS WAIT_TIME=$((WAIT_TIME + POLL_INTERVAL_SECONDS)) done return 1 } # Robust restart/rebuild for Unraid restart_container() { local NAME="$1" local STATUS=$(docker inspect -f '{{.State.Status}}' "$NAME" 2>/dev/null) # If it's NOT running, use Unraid's native rebuild # This recreates the container from XML, fixing stale --network=container:xxx IDs echo "$(date): [INFO] Performing Unraid XML-based rebuild for $NAME..." if [ -f /usr/local/emhttp/plugins/dynamix.docker.manager/scripts/rebuild_container ]; then /usr/bin/php /usr/local/emhttp/plugins/dynamix.docker.manager/scripts/rebuild_container "$NAME" else echo "$(date): [ERROR] Unraid rebuild script not found! Attempting standard start." docker start "$NAME" fi } # ----------------------------------------------------------------------------- # MAIN EXECUTION # ----------------------------------------------------------------------------- # 0. PREVENT CONCURRENT RUNS if [ -e "$LOCKFILE" ]; then echo "$(date): [INFO] Another instance is running or a stale lock exists. Exiting." echo "$(date): [INFO] To manually remove the lock: rm $LOCKFILE" exit 0 fi # Create lock and ensure cleanup on exit touch "$LOCKFILE" trap 'echo "$(date): --- End VPN Watchdog ---"; rm -f "$LOCKFILE"' EXIT echo "$(date): --- Starting VPN Watchdog ---" echo "$(date): [INFO] Starting VPN Containers Watchdog check..." # 0. VALIDATION: Ensure configured containers actually exist VALID_CONTAINERS=() for CONTAINER in $CONTAINERS; do if docker inspect "$CONTAINER" >/dev/null 2>&1; then VALID_CONTAINERS+=("$CONTAINER") else echo "$(date): [WARN] Container '$CONTAINER' not found. Removing from check list." send_notification "WARNING: Invalid Container Configuration" "The container '$CONTAINER' was not found on this system and will be skipped." "warning" fi done CONTAINERS="${VALID_CONTAINERS[*]}" # If no valid containers left, exit early if [ -z "$CONTAINERS" ]; then echo "$(date): [ERROR] No valid containers to monitor. Exiting." exit 1 fi # 1. PRE-CHECK: Is VPN container itself running? echo "$(date): [INFO] Checking if $VPN_CONTAINER is running..." if ! is_container_running "$VPN_CONTAINER"; then echo "$(date): [WARN] $VPN_CONTAINER is NOT running. Polling for up to ${MAX_WAIT_SECONDS}s..." WAIT_TIME=0 while ! is_container_running "$VPN_CONTAINER" && [ $WAIT_TIME -lt $MAX_WAIT_SECONDS ]; do sleep $POLL_INTERVAL_SECONDS WAIT_TIME=$((WAIT_TIME + POLL_INTERVAL_SECONDS)) echo "$(date): [INFO] Still waiting for $VPN_CONTAINER... ($WAIT_TIME/${MAX_WAIT_SECONDS}s)" done if ! is_container_running "$VPN_CONTAINER"; then send_notification "CRITICAL: VPN Container Down" "$VPN_CONTAINER is STILL not running after ${MAX_WAIT_SECONDS}s. Watchdog is aborting." "alert" exit 1 fi send_notification "INFO: VPN Recovered" "$VPN_CONTAINER has started. Proceeding with checks." "normal" else echo "$(date): [INFO] $VPN_CONTAINER is running. Proceeding..." fi # 2. MAIN CHECK: Identify offline or stopped containers OFFLINE_CONTAINERS=() for CONTAINER in $CONTAINERS; do echo "$(date): [INFO] Checking status and connectivity for: $CONTAINER" # Check if container is running STATUS=$(docker inspect -f '{{.State.Status}}' "$CONTAINER" 2>/dev/null) if [ "$STATUS" == "running" ]; then if ! check_connectivity "$CONTAINER"; then echo "$(date): [WARN] $CONTAINER is Running but has no internet." OFFLINE_CONTAINERS+=("$CONTAINER") else echo "$(date): [INFO] $CONTAINER is ONLINE." fi elif [ -n "$STATUS" ]; then echo "$(date): [WARN] $CONTAINER is in status '$STATUS'. Adding to recovery list." OFFLINE_CONTAINERS+=("$CONTAINER") else echo "$(date): [INFO] $CONTAINER does not exist. Skipping." fi done # 3. ACTION: If containers are offline: Notify, then Restart/Rebuild if [ ${#OFFLINE_CONTAINERS[@]} -gt 0 ]; then # Send the notification first send_notification "WARNING: VPN Containers Offline" "Issues detected in: ${OFFLINE_CONTAINERS[*]}. Attempting recovery." "warning" # Perform the recovery actions for CONTAINER in "${OFFLINE_CONTAINERS[@]}"; do restart_container "$CONTAINER" done # 4. RECOVERY VERIFICATION: Use the refined polling function check_container_up "${OFFLINE_CONTAINERS[@]}" # Final status check for notification summary SUCCESSFUL=() FAILED=() for CONTAINER in "${OFFLINE_CONTAINERS[@]}"; do if check_connectivity "$CONTAINER"; then SUCCESSFUL+=("$CONTAINER") else FAILED+=("$CONTAINER") fi done # Prepare and send summary notification if [ ${#FAILED[@]} -eq 0 ]; then send_notification "SUCCESS: VPN Containers Recovered" "The following containers are back online: ${SUCCESSFUL[*]}" "normal" elif [ ${#SUCCESSFUL[@]} -eq 0 ]; then send_notification "CRITICAL: VPN Recovery Failed" "The following containers are STILL OFFLINE: ${FAILED[*]}" "alert" else send_notification "WARNING: Partial VPN Recovery" "Recovered: ${SUCCESSFUL[*]}. STILL OFFLINE: ${FAILED[*]}" "warning" fi fi echo "$(date): [INFO] VPN Containers Watchdog check complete."
fazi13
Members
-
Joined
-
Last visited