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