97 lines
No EOL
2.9 KiB
Bash
97 lines
No EOL
2.9 KiB
Bash
#!/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 "=== Проверка завершена ===" |