🚀 Часть 1: Подготовка системы
1.1 Установка необходимых пакетов
apt update && apt install -y lm-sensors smartmontools hddtemp curl
sensors-detect --auto
1.2 Создание бота в Nextcloud Talk
На сервере Nextcloud (через SSH) выполнить:
sudo -u www-data php occ talk:bot:create -s "<СЕКРЕТНЫЙ_КЛЮЧ>" "<ИМЯ_БОТА>"
пример:
sudo -u www-data php occ talk:bot:create -s "7DcTYCuILzgKmqyXJ7JC6FCADAkIdbPDR2K0oCZF1" "ProxmoxMonitor"
Полученные данные сохранить:
IDбота (выдаст после создания, например1)Секретный ключ(который указали с флагом-s)- Токен комнаты (из URL чата:
https://cloud.example.com/index.php/call/ТОКЕН)
1.3 Добавление бота в комнату
В веб-интерфейсе Nextcloud Talk:
- Зайти в нужную комнату
- Нажать шестерёнку (настройки)
- Выбрать "Боты" → "Выбрать созданного бота" - "Включить"
🐍 Часть 2: Скрипт отправки сообщений
Создать файл /usr/local/bin/talk_send.sh:
#!/bin/bash
# ===== НАСТРОЙКИ (ИЗМЕНИТЬ ПОД СЕБЯ) =====
NC_URL="https://cloud.example.com"
ROOM_TOKEN="токен комнаты "
BOT_SECRET="7DcTYCuILzgKmqyXJ7JC6FCADAkIdbPDR2K0oCZF1"
# =========================================
MESSAGE="$1"
if [ -z "$MESSAGE" ]; then
echo "Usage: $0 <message>"
exit 1
fi
RANDOM_HEADER=$(openssl rand -hex 32)
SIGNATURE_DATA="${RANDOM_HEADER}${MESSAGE}"
SIGNATURE=$(echo -n "$SIGNATURE_DATA" | openssl dgst -sha256 -hmac "$BOT_SECRET" | awk '{print $2}')
curl -s -X POST "${NC_URL}/ocs/v2.php/apps/spreed/api/v1/bot/${ROOM_TOKEN}/message" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "OCS-APIRequest: true" \
-H "X-Nextcloud-Talk-Bot-Random: ${RANDOM_HEADER}" \
-H "X-Nextcloud-Talk-Bot-Signature: ${SIGNATURE}" \
-d "{\"message\":\"${MESSAGE}\"}"
echo ""
Сделать исполняемым:
chmod +x /usr/local/bin/talk_send.sh
Тестирование отправки
/usr/local/bin/talk_send.sh "Test message"
🌡️ Часть 3: Мониторинг температур
Создать файл /usr/local/bin/temp_monitor.sh:
#!/bin/bash
TALK_SEND="/usr/local/bin/talk_send.sh"
CPU_MAX=70
DISK_MAX=50
STATE_FILE="/var/tmp/temp_monitor.state"
send_alert() {
local alert_text="$1"
local timestamp=$(date +%s)
local hash=$(echo "$alert_text" | md5sum | cut -d' ' -f1)
if [ -f "$STATE_FILE" ]; then
last_sent=$(grep "^${hash}=" "$STATE_FILE" | cut -d= -f2)
if [ -n "$last_sent" ] && [ $((timestamp - last_sent)) -lt 1800 ]; then
return 0
fi
fi
$TALK_SEND "$alert_text"
grep -v "^${hash}=" "$STATE_FILE" > "${STATE_FILE}.tmp" 2>/dev/null
echo "${hash}=${timestamp}" >> "${STATE_FILE}.tmp"
mv "${STATE_FILE}.tmp" "$STATE_FILE"
logger -t temp_monitor "$alert_text"
}
touch "$STATE_FILE"
# --- CPU ---
if command -v sensors >/dev/null 2>&1; then
CPU_TEMP=$(sensors 2>/dev/null | grep -i "Package id" | head -1 | awk '{print $4}' | sed 's/[^0-9.]//g' | cut -d. -f1)
[ -z "$CPU_TEMP" ] && CPU_TEMP=$(sensors 2>/dev/null | grep -i "Core 0" | head -1 | awk '{print $3}' | sed 's/[^0-9.]//g' | cut -d. -f1)
[ -z "$CPU_TEMP" ] && CPU_TEMP=$(sensors 2>/dev/null | grep -i "CPU" | head -1 | awk '{print $3}' | sed 's/[^0-9.]//g' | cut -d. -f1)
fi
if [ -n "$CPU_TEMP" ] && [ "$CPU_TEMP" -gt "$CPU_MAX" ] 2>/dev/null; then
send_alert "🔥 CPU = ${CPU_TEMP}°C"
fi
# --- DISKS ---
if command -v smartctl >/dev/null 2>&1; then
for disk in /dev/sd? /dev/nvme?; do
[ -e "$disk" ] || continue
MODEL=$(smartctl -i "$disk" 2>/dev/null | grep -i "Device Model\|Model Number" | cut -d: -f2 | sed 's/^[ \t]*//' | head -1)
SERIAL=$(smartctl -i "$disk" 2>/dev/null | grep -i "Serial Number" | cut -d: -f2 | sed 's/^[ \t]*//' | head -1)
if [[ "$disk" == /dev/nvme* ]]; then
DISK_TEMP=$(smartctl -A "$disk" 2>/dev/null | grep -i "Temperature:" | awk '{print $2}' | sed 's/[^0-9]//g')
[ -z "$DISK_TEMP" ] && DISK_TEMP=$(smartctl -A "$disk" 2>/dev/null | grep -i "Composite Temperature" | awk '{print $4}' | sed 's/[^0-9]//g')
else
DISK_TEMP=$(smartctl -A "$disk" 2>/dev/null | grep -i "Temperature_Celsius" | awk '{print $10}')
[ -z "$DISK_TEMP" ] && DISK_TEMP=$(smartctl -A "$disk" 2>/dev/null | grep -i "Airflow_Temperature" | awk '{print $10}')
fi
[ -z "$MODEL" ] && MODEL=$(basename "$disk")
if [ -n "$DISK_TEMP" ] && [ "$DISK_TEMP" -gt "$DISK_MAX" ] 2>/dev/null; then
if [ -n "$SERIAL" ]; then
send_alert "🔥 HDD ${MODEL} (SN: ${SERIAL}) = ${DISK_TEMP}°C"
else
send_alert "🔥 HDD ${MODEL} = ${DISK_TEMP}°C"
fi
fi
done
fi
exit 0
Сделать исполняемым.
Тестирование (временно снизить порог)
В скрипте временно изменить: CPU_MAX=20, затем выполнить:
/usr/local/bin/temp_monitor.sh
Должно прийти сообщение 🔥 CPU = 37°C (или ваше значение). После теста вернуть порог обратно на 70.
🔄 Часть 4: Мониторинг статуса VM (Start/Stop)
4.1 Создание универсального хука
Создать файл /var/lib/vz/snippets/vm_universal_notify.sh:
#!/bin/bash
TALK_SEND="/usr/local/bin/talk_send.sh"
if [ -z "$1" ]; then
exit 0
fi
VMID=$1
PHASE=${2:-"manual"}
VMNAME=$(qm config $VMID 2>/dev/null | grep ^name | awk '{print $2}')
[ -z "$VMNAME" ] && VMNAME="unknown"
send_notification() {
local msg="$1"
[ -x "$TALK_SEND" ] && $TALK_SEND "$msg"
}
case "$PHASE" in
post-start)
send_notification "✅ VM $VMID ($VMNAME) started"
;;
pre-stop)
send_notification "🛑 VM $VMID ($VMNAME) is stopping"
;;
post-stop)
send_notification "⏹️ VM $VMID ($VMNAME) stopped"
;;
esac
exit 0
Сделать исполняемым:
chmod +x /var/lib/vz/snippets/vm_universal_notify.sh
4.2 Назначение хука для существующих VM
qm set 101 --hookscript local:snippets/vm_universal_notify.sh
qm set 102 --hookscript local:snippets/vm_universal_notify.sh
Заменить 101, 102 на свои VMID (узнать через qm list).
4.3 (Опционально) Автоматическое назначение хука новым VM
Добавить в crontab:
* * * * * for vmid in $(qm list | awk 'NR>1 {print $1}'); do qm config $vmid | grep -q "hookscript: local:snippets/vm_universal_notify.sh" || qm set $vmid --hookscript local:snippets/vm_universal_notify.sh; done
4.4 Тестирование
qm stop 101 && qm start 101
Проверить чат — должны прийти сообщения о остановке и запуске.
💾 Часть 5: Мониторинг ZFS RAID
Создать файл /usr/local/bin/check_zfs.sh:
#!/bin/bash
TALK_SEND="/usr/local/bin/talk_send.sh"
POOL_STATUS=$(zpool status -x)
if [[ "$POOL_STATUS" != *"all pools are healthy"* ]]; then
$TALK_SEND "⚠️ ZFS Alert: $POOL_STATUS"
fi
Тестирование (имитация ошибки)
# Временно изменить скрипт, добавив в начало: POOL_STATUS="degraded"
/usr/local/bin/check_zfs.sh
⏰ Часть 6: Настройка cron (автоматический запуск)
crontab -e
# Температуры каждые 5 минут
*/5 * * * * /usr/local/bin/temp_monitor.sh
# ZFS каждый час
0 * * * * /usr/local/bin/check_zfs.sh
# (Опционально) Автоматическое назначение хука новым VM
* * * * * for vmid in $(qm list | awk 'NR>1 {print $1}'); do qm config $vmid | grep -q "hookscript: local:snippets/vm_universal_notify.sh" || qm set $vmid --hookscript local:snippets/vm_universal_notify.sh; done
🔧 Часть 7: Возможные проблемы и решения
| Проблема | Решение |
|---|---|
talk_send.sh не отправляет |
Проверить URL, токен комнаты, секрет. Выполнить вручную curl к API |
| Температура CPU не определяется | Выполнить sensors, скорректировать ключевые слова в скрипте |
| Хук не срабатывает | Проверить права на файл (chmod +x), путь local:snippets/ |
| ZFS не мониторится | Проверить наличие пулов (zpool list) |
| Сообщения дублируются | Защита от дублей уже встроена (30 минут) |
- Войдите или зарегистрируйтесь, чтобы оставлять комментарии