From 1b8eaf4d9db5338207272c3da067033a5a8840c8 Mon Sep 17 00:00:00 2001 From: adminalt Date: Mon, 14 Sep 2026 10:34:33 +0000 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D1=82?= =?UTF-8?q?=D1=8C=20install/monitor.sh?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- install/monitor.sh | 97 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 install/monitor.sh diff --git a/install/monitor.sh b/install/monitor.sh new file mode 100644 index 0000000..dbab107 --- /dev/null +++ b/install/monitor.sh @@ -0,0 +1,97 @@ +#!/usr/bin/env bash +# +# Мониторинг живости трёх инбаундов + алерт в Telegram. +# Установка в cron: */15 * * * * /opt/vpn-setup/monitor.sh >> /var/log/vpn-monitor.log 2>&1 +# +set -euo pipefail + +WORKDIR="/opt/vpn-setup" +source "$WORKDIR/params.env" + +STATE_FILE="$WORKDIR/monitor_state" +touch "$STATE_FILE" + +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" +} + +send_alert() { + local message="$1" + log "ALERT: $message" + if [[ -n "${TELEGRAM_BOT_TOKEN:-}" && -n "${TELEGRAM_CHAT_ID:-}" ]]; then + curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \ + -d chat_id="${TELEGRAM_CHAT_ID}" \ + -d text="🚨 VPN Monitor: ${message}" > /dev/null || true + fi +} + +was_down() { + grep -q "^$1:down$" "$STATE_FILE" 2>/dev/null +} + +mark_state() { + local name="$1" + local state="$2" + grep -v "^$name:" "$STATE_FILE" > "${STATE_FILE}.tmp" 2>/dev/null || true + echo "$name:$state" >> "${STATE_FILE}.tmp" + mv "${STATE_FILE}.tmp" "$STATE_FILE" +} + +check_tcp_port() { + local name="$1" + local port="$2" + if timeout 5 bash -c "cat < /dev/null > /dev/tcp/127.0.0.1/${port}" 2>/dev/null; then + if was_down "$name"; then + send_alert "${name} восстановлен (порт ${port} снова отвечает)" + fi + mark_state "$name" "up" + log "OK: $name (tcp/$port)" + else + if ! was_down "$name"; then + send_alert "${name} НЕ отвечает (порт ${port}). Возможна блокировка." + fi + mark_state "$name" "down" + log "FAIL: $name (tcp/$port)" + fi +} + +check_systemd_service() { + local name="$1" + local service="$2" + if systemctl is-active --quiet "$service"; then + if was_down "$name-svc"; then + send_alert "Сервис ${service} снова запущен" + fi + mark_state "$name-svc" "up" + else + if ! was_down "$name-svc"; then + send_alert "Сервис ${service} УПАЛ (systemd). Пробую перезапустить." + fi + mark_state "$name-svc" "down" + systemctl restart "$service" || true + fi +} + +log "=== Проверка начата ===" + +check_systemd_service "xray" "xray" +check_systemd_service "hysteria" "hysteria-server" + +check_tcp_port "VLESS-XHTTP-443" 443 +check_tcp_port "VLESS-TCP-8443" 8443 + +if [[ -n "${DOMAIN:-}" ]]; then + CERT_FILE="/etc/letsencrypt/live/${DOMAIN}/fullchain.pem" + if [[ -f "$CERT_FILE" ]]; then + EXPIRY_DATE=$(openssl x509 -enddate -noout -in "$CERT_FILE" | cut -d= -f2) + EXPIRY_EPOCH=$(date -d "$EXPIRY_DATE" +%s) + NOW_EPOCH=$(date +%s) + DAYS_LEFT=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 )) + if [[ $DAYS_LEFT -lt 14 ]]; then + send_alert "Сертификат ${DOMAIN} истекает через ${DAYS_LEFT} дней. Проверьте certbot renew." + fi + log "Сертификат действителен ещё ${DAYS_LEFT} дней" + fi +fi + +log "=== Проверка завершена ===" \ No newline at end of file