Update file 11-backup.md
This commit is contained in:
parent
fec26119d1
commit
48cd364263
@ -28,7 +28,7 @@
|
|||||||
| **Расписание** | ✅ | 2 раза в день (02:30 и 22:30) |
|
| **Расписание** | ✅ | 2 раза в день (02:30 и 22:30) |
|
||||||
| **Retention** | ✅ | 14 последних, 7 ежедневных, 4 недельных, 4 месячных |
|
| **Retention** | ✅ | 14 последних, 7 ежедневных, 4 недельных, 4 месячных |
|
||||||
| **Режим** | ✅ | Snapshot (без остановки сервисов) |
|
| **Режим** | ✅ | Snapshot (без остановки сервисов) |
|
||||||
| **Уведомления** | ✅ | Telegram-бот через Python-реле (порт 8085) |
|
| **Уведомления** | ✅ | Telegram-бот через прокси (XRay + Redsocks) |
|
||||||
|
|
||||||
### 📊 Архитектура
|
### 📊 Архитектура
|
||||||
|
|
||||||
@ -39,8 +39,7 @@ graph TD
|
|||||||
A -->|Network| D["Proxmox Backup Server<br/>Olimpbs 192.168.1.199"]
|
A -->|Network| D["Proxmox Backup Server<br/>Olimpbs 192.168.1.199"]
|
||||||
D --> E["Datastore: olimpbkp<br/>1 TB LVM"]
|
D --> E["Datastore: olimpbkp<br/>1 TB LVM"]
|
||||||
E --> F["/var/lib/proxmox-backup/olimpbkp"]
|
E --> F["/var/lib/proxmox-backup/olimpbkp"]
|
||||||
D -->|Python Relay 8085| G["Telegram API<br/>api.telegram.org"]
|
D -->|HTTPS via proxy| G["Telegram API<br/>api.telegram.org"]
|
||||||
G -->|SOCKS5 1080| H["XRay Proxy<br/>2.27.50.20:2054"]
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -279,19 +278,272 @@ proxmox-backup-client verify ct/201/2026-04-11T13:19:03Z \
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📦 Уведомления в Telegram (через Python-реле)
|
## 📦 Уведомления в Telegram
|
||||||
|
|
||||||
### 🎯 Цель
|
### 🎯 Цель
|
||||||
Получать красивые уведомления в Telegram о статусе бэкапов с форматированием времени и эмодзи.
|
Получать уведомления в Telegram об успешных/неудачных бэкапах с Proxmox Backup Server, без изменений на гипервизоре.
|
||||||
|
В системе настроено **два независимых канала** уведомлений в Telegram:
|
||||||
|
|
||||||
|
| Тип | Источник | Сервер | Порт реле | Что уведомляет |
|
||||||
|
|-----|----------|--------|-----------|----------------|
|
||||||
|
| **PBS Backup Notifications** | Proxmox Backup Server | 192.168.1.199 | 8085 | ✅ Успешные/❌ неудачные бэкапы |
|
||||||
|
| **Grafana Alerts** | VictoriaMetrics + Grafana | 192.168.1.208 | 8085 | ⚠️ Бэкапы старше 24 часов |
|
||||||
|
|
||||||
### 📋 Предварительные требования
|
### 📋 Предварительные требования
|
||||||
- Сервер с доступом в интернет через прокси (XRay SOCKS5)
|
- PBS сервер (192.168.1.199) с доступом в интернет через прокси
|
||||||
- Telegram бот: токен и chat_id
|
- Telegram бот: токен и chat_id
|
||||||
- Python 3 установлен
|
- Прокси: VLESS+Reality на `2.27.50.20:2054`
|
||||||
|
|
||||||
|
### 🔧 Настройка прокси (XRay + Redsocks + iptables)
|
||||||
|
|
||||||
|
**1. Установка XRay клиента**
|
||||||
|
```bash
|
||||||
|
# Установка зависимостей
|
||||||
|
apt update && apt install unzip curl iptables -y
|
||||||
|
|
||||||
|
# Скачиваем XRay
|
||||||
|
cd /tmp
|
||||||
|
curl -L -o xray.zip https://github.com/XTLS/Xray-core/releases/latest/download/Xray-linux-64.zip
|
||||||
|
unzip xray.zip
|
||||||
|
chmod +x xray
|
||||||
|
mv xray geoip.dat geosite.dat /usr/local/bin/
|
||||||
|
|
||||||
|
# Проверка
|
||||||
|
xray version
|
||||||
|
```
|
||||||
|
|
||||||
|
**2. Конфигурация XRay**
|
||||||
|
```bash
|
||||||
|
mkdir -p /usr/local/etc/xray
|
||||||
|
|
||||||
|
cat > /usr/local/etc/xray/config.json << 'EOF'
|
||||||
|
{
|
||||||
|
"log": {"loglevel": "warning"},
|
||||||
|
"inbounds": [{"port": 1080, "listen": "127.0.0.1", "protocol": "socks", "settings": {"auth": "noauth", "udp": true}}],
|
||||||
|
"outbounds": [
|
||||||
|
{
|
||||||
|
"protocol": "vless",
|
||||||
|
"settings": {
|
||||||
|
"vnext": [{
|
||||||
|
"address": "2.27.50.20",
|
||||||
|
"port": 2054,
|
||||||
|
"users": [{"id": "68f44a38-396d-48da-b832-79b5dc5716ab", "encryption": "none", "level": 8}]
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"streamSettings": {
|
||||||
|
"network": "xhttp",
|
||||||
|
"security": "reality",
|
||||||
|
"realitySettings": {
|
||||||
|
"serverName": "cloud.zailon.ru",
|
||||||
|
"publicKey": "TOyddQCTdSpycmO20uiLOqMABuKabpwVhw57tWmvJws",
|
||||||
|
"shortId": "174fc0",
|
||||||
|
"spiderX": "/"
|
||||||
|
},
|
||||||
|
"xhttpSettings": {
|
||||||
|
"host": "",
|
||||||
|
"path": "/remote.php/dav/upload",
|
||||||
|
"mode": "stream-one"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "proxy"
|
||||||
|
},
|
||||||
|
{"protocol": "freedom", "tag": "direct"}
|
||||||
|
],
|
||||||
|
"routing": {
|
||||||
|
"rules": [
|
||||||
|
{"type": "field", "ip": ["geoip:private"], "outboundTag": "direct"},
|
||||||
|
{"type": "field", "domain": ["api.telegram.org"], "outboundTag": "proxy"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
**3. Запуск XRay как сервис**
|
||||||
|
```bash
|
||||||
|
cat > /etc/systemd/system/xray-client.service << 'EOF'
|
||||||
|
[Unit]
|
||||||
|
Description=XRay Client
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=/usr/local/bin/xray run -config /usr/local/etc/xray/config.json
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=5
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable --now xray-client
|
||||||
|
systemctl status xray-client
|
||||||
|
```
|
||||||
|
|
||||||
|
**4. Установка и настройка Redsocks**
|
||||||
|
```bash
|
||||||
|
# Установка
|
||||||
|
apt install redsocks -y
|
||||||
|
|
||||||
|
# Конфигурация
|
||||||
|
cat > /etc/redsocks.conf << 'EOF'
|
||||||
|
base {
|
||||||
|
log_debug = off;
|
||||||
|
log_info = off;
|
||||||
|
log = stderr;
|
||||||
|
daemon = on;
|
||||||
|
redirector = iptables;
|
||||||
|
}
|
||||||
|
|
||||||
|
redsocks {
|
||||||
|
bind = "0.0.0.0:12345";
|
||||||
|
relay = "127.0.0.1:1080";
|
||||||
|
type = socks5;
|
||||||
|
autoproxy = 0;
|
||||||
|
timeout = 10;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Запуск
|
||||||
|
systemctl enable --now redsocks
|
||||||
|
```
|
||||||
|
|
||||||
|
**5. Настройка iptables для Telegram**
|
||||||
|
```bash
|
||||||
|
cat > /usr/local/bin/telegram-proxy.sh << 'EOF'
|
||||||
|
#!/bin/bash
|
||||||
|
iptables -t nat -F TELEGRAM_PROXY 2>/dev/null
|
||||||
|
iptables -t nat -X TELEGRAM_PROXY 2>/dev/null
|
||||||
|
iptables -t nat -N TELEGRAM_PROXY
|
||||||
|
|
||||||
|
# Telegram IP ranges
|
||||||
|
iptables -t nat -A TELEGRAM_PROXY -p tcp -d 149.154.160.0/20 -j REDIRECT --to-ports 12345
|
||||||
|
iptables -t nat -A TELEGRAM_PROXY -p tcp -d 91.108.4.0/22 -j REDIRECT --to-ports 12345
|
||||||
|
|
||||||
|
iptables -t nat -A OUTPUT -p tcp --dport 443 -j TELEGRAM_PROXY
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chmod +x /usr/local/bin/telegram-proxy.sh
|
||||||
|
/usr/local/bin/telegram-proxy.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
**6. Проверка соединения**
|
||||||
|
```bash
|
||||||
|
curl -s "https://api.telegram.org/bot<YOUR_BOT_TOKEN>/getMe"
|
||||||
|
```
|
||||||
|
*Ожидаемый результат*: JSON с информацией о боте.
|
||||||
|
|
||||||
|
### 🔧 Скрипт уведомлений
|
||||||
|
|
||||||
|
**7. Создание скрипта**
|
||||||
|
```bash
|
||||||
|
cat > /usr/local/bin/pbs-backup-notify.sh << 'EOF'
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
TOKEN="YOUR_BOT_TOKEN"
|
||||||
|
CHAT="YOUR_CHAT_ID"
|
||||||
|
ARCHIVE="/var/log/proxmox-backup/tasks/archive"
|
||||||
|
STATE="/var/run/pbs-notify-lastline"
|
||||||
|
|
||||||
|
# Получаем последнюю обработанную строку
|
||||||
|
LAST_LINE=$(cat $STATE 2>/dev/null || echo 0)
|
||||||
|
CURR_LINE=$(wc -l < $ARCHIVE)
|
||||||
|
|
||||||
|
# Если файл уменьшился - начинаем сначала
|
||||||
|
if [ "$CURR_LINE" -lt "$LAST_LINE" ]; then
|
||||||
|
LAST_LINE=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Читаем новые строки
|
||||||
|
if [ "$CURR_LINE" -gt "$LAST_LINE" ]; then
|
||||||
|
tail -n +$((LAST_LINE + 1)) $ARCHIVE | while IFS= read -r line; do
|
||||||
|
# Только backup задачи
|
||||||
|
if echo "$line" | grep -q ":backup:"; then
|
||||||
|
# Извлекаем имя бэкапа (конвертируем \x3a в :)
|
||||||
|
BACKUP=$(echo "$line" | grep -oP 'backup:\K[^:]+' | sed 's/\\x3a/:/g')
|
||||||
|
STATUS=$(echo "$line" | grep -oP 'OK|FAILED|ERROR')
|
||||||
|
TIME=$(date '+%Y-%m-%d %H:%M:%S')
|
||||||
|
|
||||||
|
if [ "$STATUS" = "OK" ]; then
|
||||||
|
curl -s -X POST "https://api.telegram.org/bot$TOKEN/sendMessage" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"chat_id\":\"$CHAT\",\"text\":\"✅ *Backup Success*\\n📦 $BACKUP\\n⏰ $TIME\",\"parse_mode\":\"Markdown\"}" > /dev/null
|
||||||
|
else
|
||||||
|
curl -s -X POST "https://api.telegram.org/bot$TOKEN/sendMessage" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"chat_id\":\"$CHAT\",\"text\":\"❌ *Backup Failed*\\n📦 $BACKUP\\n⏰ $TIME\\n📝 Status: $STATUS\",\"parse_mode\":\"Markdown\"}" > /dev/null
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Сохраняем позицию
|
||||||
|
echo $CURR_LINE > $STATE
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chmod +x /usr/local/bin/pbs-backup-notify.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
**8. Настройка Cron (каждые 5 минут)**
|
||||||
|
```bash
|
||||||
|
echo "*/5 * * * * root /usr/local/bin/pbs-backup-notify.sh" >> /etc/cron.d/pbs-notify
|
||||||
|
```
|
||||||
|
|
||||||
|
**9. Инициализация и тест**
|
||||||
|
```bash
|
||||||
|
# Сброс состояния для теста
|
||||||
|
echo "0" > /var/run/pbs-notify-lastline
|
||||||
|
|
||||||
|
# Запуск вручную
|
||||||
|
/usr/local/bin/pbs-backup-notify.sh
|
||||||
|
|
||||||
|
# Проверка состояния
|
||||||
|
cat /var/run/pbs-notify-lastline
|
||||||
|
wc -l < /var/log/proxmox-backup/tasks/archive
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### 📝 Переменные для замены
|
||||||
|
|
||||||
|
| Переменная | Описание | Пример |
|
||||||
|
|------------|----------|--------|
|
||||||
|
| `YOUR_BOT_TOKEN` | Токен Telegram бота | `7657027552:AAHQ6OGDRbm6wtqh_4GOQr7jd6C0BAQMyF4` |
|
||||||
|
| `YOUR_CHAT_ID` | ID чата для уведомлений | `292909723` |
|
||||||
|
| `address` | Адрес прокси-сервера | `2.27.50.20` |
|
||||||
|
| `port` | Порт прокси | `2054` |
|
||||||
|
| `id` | UUID пользователя VLESS | `68f44a38-396d-48da-b832-79b5dc5716ab` |
|
||||||
|
| `publicKey` | Публичный ключ Reality | `TOyddQCTdSpycmO20uiLOqMABuKabpwVhw57tWmvJws` |
|
||||||
|
| `serverName` | Домен для Reality | `cloud.zailon.ru` |
|
||||||
|
|
||||||
|
### 📁 Файлы конфигурации
|
||||||
|
|
||||||
|
| Файл | Назначение |
|
||||||
|
|------|------------|
|
||||||
|
| `/usr/local/etc/xray/config.json` | Конфиг XRay прокси |
|
||||||
|
| `/etc/redsocks.conf` | Конфиг Redsocks |
|
||||||
|
| `/usr/local/bin/telegram-proxy.sh` | Правила iptables для Telegram |
|
||||||
|
| `/usr/local/bin/pbs-backup-notify.sh` | Скрипт уведомлений |
|
||||||
|
| `/var/run/pbs-notify-lastline` | Позиция последнего прочитанного лога |
|
||||||
|
| `/etc/cron.d/pbs-notify` | Cron задача |
|
||||||
|
|
||||||
|
## 📦 Настройка уведомлений из Grafana в Telegram
|
||||||
|
|
||||||
|
### 🎯 Цель
|
||||||
|
Настроить отправку алертов из Grafana в Telegram с красивым форматированием, эмодзи и автоматическим преобразованием времени.
|
||||||
|
|
||||||
|
### 📋 Архитектура
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
A["Grafana<br/>192.168.1.208"] -->|HTTP POST| B["Python Relay<br/>localhost:8085"]
|
||||||
|
B -->|SOCKS5| C["XRay Client<br/>127.0.0.1:1080"]
|
||||||
|
C -->|HTTPS| D["Telegram API<br/>api.telegram.org"]
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 🔧 Настройка Python-реле (универсальный способ)
|
### 🔧 Шаг 1: Установка Python-реле
|
||||||
|
|
||||||
**1. Создай скрипт реле:**
|
**1. Создай скрипт реле:**
|
||||||
|
|
||||||
@ -309,6 +561,7 @@ CHAT_ID = "292909723"
|
|||||||
PROXY = "socks5://127.0.0.1:1080"
|
PROXY = "socks5://127.0.0.1:1080"
|
||||||
|
|
||||||
def format_duration(seconds):
|
def format_duration(seconds):
|
||||||
|
"""Преобразует секунды в читаемый формат"""
|
||||||
try:
|
try:
|
||||||
sec = float(seconds)
|
sec = float(seconds)
|
||||||
if sec < 60:
|
if sec < 60:
|
||||||
@ -325,9 +578,11 @@ def format_duration(seconds):
|
|||||||
return str(seconds)
|
return str(seconds)
|
||||||
|
|
||||||
def get_icon(backup):
|
def get_icon(backup):
|
||||||
|
"""Выбирает эмодзи по имени бэкапа"""
|
||||||
return "💻" if backup.startswith('vm-') else "📦" if backup.startswith('ct-') else "🗄️"
|
return "💻" if backup.startswith('vm-') else "📦" if backup.startswith('ct-') else "🗄️"
|
||||||
|
|
||||||
def send_telegram(text):
|
def send_telegram(text):
|
||||||
|
"""Отправляет текст в Telegram через прокси"""
|
||||||
try:
|
try:
|
||||||
cmd = [
|
cmd = [
|
||||||
'curl', '-sx', PROXY, '-s',
|
'curl', '-sx', PROXY, '-s',
|
||||||
@ -342,6 +597,7 @@ def send_telegram(text):
|
|||||||
|
|
||||||
def handle_client(client_socket, addr):
|
def handle_client(client_socket, addr):
|
||||||
try:
|
try:
|
||||||
|
# Читаем запрос частями
|
||||||
data = b""
|
data = b""
|
||||||
client_socket.settimeout(2)
|
client_socket.settimeout(2)
|
||||||
while True:
|
while True:
|
||||||
@ -356,6 +612,7 @@ def handle_client(client_socket, addr):
|
|||||||
data = data.decode('utf-8', errors='ignore')
|
data = data.decode('utf-8', errors='ignore')
|
||||||
body = data.split('\r\n\r\n', 1)[1] if '\r\n\r\n' in data else data
|
body = data.split('\r\n\r\n', 1)[1] if '\r\n\r\n' in data else data
|
||||||
|
|
||||||
|
# Парсим JSON от Grafana
|
||||||
backups = re.findall(r'"backup"\s*:\s*"([^"]+)"', body)
|
backups = re.findall(r'"backup"\s*:\s*"([^"]+)"', body)
|
||||||
statuses = re.findall(r'"status"\s*:\s*"([^"]+)"', body)
|
statuses = re.findall(r'"status"\s*:\s*"([^"]+)"', body)
|
||||||
values = re.findall(r'value=([\d.]+)', body)
|
values = re.findall(r'value=([\d.]+)', body)
|
||||||
@ -375,6 +632,7 @@ def handle_client(client_socket, addr):
|
|||||||
status = statuses[idx] if idx < len(statuses) else "unknown"
|
status = statuses[idx] if idx < len(statuses) else "unknown"
|
||||||
icon = get_icon(backup)
|
icon = get_icon(backup)
|
||||||
|
|
||||||
|
# Форматируем время из секунд
|
||||||
if len(values) >= (idx * 2 + 1):
|
if len(values) >= (idx * 2 + 1):
|
||||||
seconds = float(values[idx * 2])
|
seconds = float(values[idx * 2])
|
||||||
human_time = format_duration(seconds)
|
human_time = format_duration(seconds)
|
||||||
@ -401,14 +659,16 @@ def handle_client(client_socket, addr):
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Запуск сервера
|
||||||
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
server.bind(('0.0.0.0', PORT))
|
server.bind(('0.0.0.0', PORT))
|
||||||
server.listen(10)
|
server.listen(10)
|
||||||
print(f"▶ Relay on {PORT}", file=sys.stderr)
|
print(f"▶ Telegram Relay on {PORT}", file=sys.stderr)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
client, addr = server.accept()
|
client, addr = server.accept()
|
||||||
|
print(f"← {addr}", file=sys.stderr)
|
||||||
handle_client(client, addr)
|
handle_client(client, addr)
|
||||||
EOF
|
EOF
|
||||||
chmod +x /usr/local/bin/telegram-relay.py
|
chmod +x /usr/local/bin/telegram-relay.py
|
||||||
@ -440,10 +700,10 @@ systemctl daemon-reload
|
|||||||
systemctl enable --now telegram-relay
|
systemctl enable --now telegram-relay
|
||||||
```
|
```
|
||||||
|
|
||||||
**3. Проверь что работает:**
|
**3. Проверь работу:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Статус сервиса
|
# Проверка статуса
|
||||||
systemctl status telegram-relay
|
systemctl status telegram-relay
|
||||||
|
|
||||||
# Проверка порта
|
# Проверка порта
|
||||||
@ -457,88 +717,107 @@ curl -X POST http://127.0.0.1:8085 -d "🎉 Test message"
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 🔧 Настройка в Grafana (если используешь мониторинг)
|
### 🔧 Шаг 2: Настройка Contact Point в Grafana
|
||||||
|
|
||||||
**1. Contact Points → Add new:**
|
**1. Открой Grafana:**
|
||||||
|
- Перейди: **Alerting** → **Contact points**
|
||||||
|
- Нажми **+ Add contact point**
|
||||||
|
|
||||||
|
**2. Заполни поля:**
|
||||||
|
|
||||||
| Поле | Значение |
|
| Поле | Значение |
|
||||||
|------|----------|
|
|------|----------|
|
||||||
| **Name** | `Telegram Relay` |
|
| **Name** | `Telegram Relay` |
|
||||||
| **Type** | `Webhook` |
|
| **Integration** | `Webhook` |
|
||||||
| **URL** | `http://192.168.1.208:8085` |
|
| **URL** | `http://127.0.0.1:8085` |
|
||||||
| **HTTP Method** | `POST` |
|
| **HTTP Method** | `POST` |
|
||||||
| **Max Alerts** | `0` (без лимита) |
|
| **Max Alerts** | `0` (без лимита) |
|
||||||
|
|
||||||
**2. Сообщение (Message):**
|
**3. Сообщение (Message):**
|
||||||
```bash
|
|
||||||
|
```text
|
||||||
{{ range .Alerts }}
|
{{ range .Alerts }}
|
||||||
📦 {{ .Labels.backup }}
|
📦 {{ .Labels.backup }}
|
||||||
⏱ {{ .Annotations.description }}
|
⏱ {{ .Annotations.description }}
|
||||||
Status: {{ if eq .Status "firing" }}🔥{{ else }}✅{{ end }} {{ .Status }}
|
Status: {{ if eq .Status "firing" }}🔥{{ else }}✅{{ end }} {{ .Status }}
|
||||||
|
---
|
||||||
{{ end }}
|
{{ end }}
|
||||||
```
|
```
|
||||||
|
|
||||||
**3. В Alert Rule → Annotations → Description:**
|
**4. Сохрани:**
|
||||||
```bash
|
- Нажми **Save contact point**
|
||||||
|
- Нажми **Test** — должно прийти сообщение
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🔧 Шаг 3: Создание Alert Rule
|
||||||
|
|
||||||
|
**1. Перейди:** **Alerting** → **Alert rules** → **+ New alert rule**
|
||||||
|
|
||||||
|
**2. Query и условие:**
|
||||||
|
|
||||||
|
| Поле | Значение |
|
||||||
|
|------|----------|
|
||||||
|
| **Query** | `time() - last_over_time(pbs_backup_timestamp[1h])/1000` |
|
||||||
|
| **Alert condition** | `A is above 86400` |
|
||||||
|
| **Evaluation group** | `Backup alerts` (создать новый) |
|
||||||
|
| **Evaluation interval** | `1m` |
|
||||||
|
| **Pending period** | `1m` |
|
||||||
|
|
||||||
|
**3. Annotations → Description:**
|
||||||
|
|
||||||
|
```text
|
||||||
{{ .Value }}
|
{{ .Value }}
|
||||||
```
|
```
|
||||||
|
|
||||||
*(Python-скрипт сам превратит секунды в "11 ч 35 мин")*
|
*(Python-скрипт сам превратит секунды в "11 ч 35 мин")*
|
||||||
|
|
||||||
**4. Протестируй:**
|
**4. Notifications:**
|
||||||
- Contact Point → **Test**
|
- Выбери Contact Point: `Telegram Relay`
|
||||||
- Должно прийти красивое уведомление
|
|
||||||
|
**5. Сохрани правило**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 🔧 Настройка в Proxmox Backup Server (прямые уведомления)
|
### 🔧 Шаг 4: Проверка
|
||||||
|
|
||||||
Если хочешь уведомления напрямую из PBS (без Grafana):
|
**1. Проверка реле:**
|
||||||
|
|
||||||
**1. Создай endpoint (webhook):**
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
proxmox-backup-manager notification endpoint webhook create telegram \
|
# Логи реле
|
||||||
--url "http://192.168.1.208:8085" \
|
journalctl -u telegram-relay -f
|
||||||
--method post \
|
|
||||||
--header "Content-Type: application/json"
|
# Тестовый запрос
|
||||||
|
curl -X POST http://127.0.0.1:8085 \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"text":"✅ Grafana relay test"}'
|
||||||
```
|
```
|
||||||
|
|
||||||
**2. Создай matcher для ошибок:**
|
**2. Проверка XRay:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
proxmox-backup-manager notification matcher create backup-error \
|
# Статус XRay
|
||||||
--endpoint telegram \
|
systemctl status xray-client
|
||||||
--cal-filter backup \
|
|
||||||
--severity error
|
# Тест соединения с Telegram
|
||||||
|
curl -sx socks5://127.0.0.1:1080 \
|
||||||
|
https://api.telegram.org/bot7657027552:AAHQ6OGDRbm6wtqh_4GOQr7jd6C0BAQMyF4/getMe
|
||||||
```
|
```
|
||||||
|
|
||||||
**3. Создай matcher для успехов (опционально):**
|
**3. Тест алерта:**
|
||||||
|
- В Grafana: Contact Point → **Test**
|
||||||
```bash
|
- Должно прийти сообщение в Telegram
|
||||||
proxmox-backup-manager notification matcher create backup-success \
|
|
||||||
--endpoint telegram \
|
|
||||||
--cal-filter backup \
|
|
||||||
--severity info
|
|
||||||
```
|
|
||||||
|
|
||||||
**4. Протестируй:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
proxmox-backup-manager notification target test telegram
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 📝 Переменные для замены
|
### 📝 Переменные для замены
|
||||||
|
|
||||||
| Переменная | Описание | Пример |
|
| Переменная | Описание | Значение |
|
||||||
|------------|----------|--------|
|
|------------|----------|----------|
|
||||||
| `BOT_TOKEN` | Токен Telegram бота | `7657027552:AAHQ6OGDRbm6wtqh_4GOQr7jd6C0BAQMyF4` |
|
| `BOT_TOKEN` | Токен Telegram бота | `7657027552:AAHQ6OGDRbm6wtqh_4GOQr7jd6C0BAQMyF4` |
|
||||||
| `CHAT_ID` | ID чата для уведомлений | `292909723` |
|
| `CHAT_ID` | ID чата для уведомлений | `292909723` |
|
||||||
| `PROXY` | SOCKS5 прокси (XRay) | `socks5://127.0.0.1:1080` |
|
| `PROXY` | SOCKS5 прокси | `socks5://127.0.0.1:1080` |
|
||||||
| `PORT` | Порт реле (локальный) | `8085` |
|
| `PORT` | Порт реле | `8085` |
|
||||||
| `GRAFANA_HOST` | IP сервера с Grafana | `192.168.1.208` |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -548,32 +827,7 @@ proxmox-backup-manager notification target test telegram
|
|||||||
|------|------------|
|
|------|------------|
|
||||||
| `/usr/local/bin/telegram-relay.py` | Python-скрипт реле |
|
| `/usr/local/bin/telegram-relay.py` | Python-скрипт реле |
|
||||||
| `/etc/systemd/system/telegram-relay.service` | systemd-юнит |
|
| `/etc/systemd/system/telegram-relay.service` | systemd-юнит |
|
||||||
| `/var/log/syslog` | Логи (через journalctl) |
|
| `/etc/grafana/provisioning/alerting/` | Конфиги алертов Grafana |
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 🧪 Тестирование
|
|
||||||
|
|
||||||
**1. Проверка соединения с Telegram:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl -sx socks5://127.0.0.1:1080 \
|
|
||||||
https://api.telegram.org/bot$BOT_TOKEN/getMe
|
|
||||||
```
|
|
||||||
|
|
||||||
**2. Проверка реле:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl -X POST http://127.0.0.1:8085 \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"text":"✅ Relay is working!"}'
|
|
||||||
```
|
|
||||||
|
|
||||||
**3. Просмотр логов:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
journalctl -u telegram-relay -f
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -581,25 +835,28 @@ journalctl -u telegram-relay -f
|
|||||||
|
|
||||||
| Проблема | Решение |
|
| Проблема | Решение |
|
||||||
|----------|---------|
|
|----------|---------|
|
||||||
| Не приходит сообщение | Проверь `journalctl -u telegram-relay -n 20` |
|
| Не приходит сообщение | `journalctl -u telegram-relay -n 20` |
|
||||||
| Ошибка 400 от Telegram | Убери `parse_mode` или экранируй спецсимволы |
|
| Ошибка 400 от Telegram | Убери `parse_mode` или экранируй спецсимволы |
|
||||||
| Реле не слушает порт | `systemctl restart telegram-relay` |
|
| Реле не слушает порт | `systemctl restart telegram-relay` |
|
||||||
| XRay не подключается | Проверь `systemctl status xray-client` |
|
| XRay не подключается | `systemctl status xray-client` |
|
||||||
| Сообщение обрезается | Скрипт разбивает на части по 5 бэкапов — это норма |
|
| Сообщение обрезается | Скрипт разбивает на части по 5 бэкапов — это норма |
|
||||||
|
| Grafana не шлёт | Проверь что Alert Rule в состоянии "Firing" |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 🎨 Формат уведомления
|
### 🎨 Пример уведомления
|
||||||
|
|
||||||
Пример того, что придёт в Telegram:
|
```text
|
||||||
```mermaid
|
|
||||||
🚨 Backup Alert
|
🚨 Backup Alert
|
||||||
|
|
||||||
📦 ct-201
|
📦 ct-201
|
||||||
⏱ Последний бэкап: 11 ч 35 мин назад
|
⏱ Последний бэкап: 11 ч 35 мин назад
|
||||||
Status: 🔥 firing
|
Status: 🔥 firing
|
||||||
|
|
||||||
📦 ct-202
|
📦 ct-202
|
||||||
⏱ Последний бэкап: 11 ч 34 мин назад
|
⏱ Последний бэкап: 11 ч 34 мин назад
|
||||||
Status: 🔥 firing
|
Status: 🔥 firing
|
||||||
|
|
||||||
💻 vm-205
|
💻 vm-205
|
||||||
⏱ Последний бэкап: 11 ч 30 мин назад
|
⏱ Последний бэкап: 11 ч 30 мин назад
|
||||||
Status: ✅ resolved
|
Status: ✅ resolved
|
||||||
@ -615,8 +872,6 @@ Status: ✅ resolved
|
|||||||
|
|
||||||
### 🔄 Обновление скрипта
|
### 🔄 Обновление скрипта
|
||||||
|
|
||||||
Если нужно изменить формат или логику:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Останови сервис
|
# Останови сервис
|
||||||
systemctl stop telegram-relay
|
systemctl stop telegram-relay
|
||||||
@ -630,7 +885,6 @@ systemctl start telegram-relay
|
|||||||
# Проверь статус
|
# Проверь статус
|
||||||
systemctl status telegram-relay
|
systemctl status telegram-relay
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Безопасность
|
## Безопасность
|
||||||
@ -646,7 +900,7 @@ systemctl status telegram-relay
|
|||||||
- **Доступ**: только из локальной сети (192.168.1.0/24)
|
- **Доступ**: только из локальной сети (192.168.1.0/24)
|
||||||
|
|
||||||
### Рекомендации
|
### Рекомендации
|
||||||
- ✅ Включить **2FA** для доступа к PBS
|
- ✅ Включить **2FA** для `root@pam`
|
||||||
- ✅ Создать **отдельного пользователя** для бэкапов (не root)
|
- ✅ Создать **отдельного пользователя** для бэкапов (не root)
|
||||||
- ✅ Настроить **firewall** на PBS сервере
|
- ✅ Настроить **firewall** на PBS сервере
|
||||||
- ✅ Регулярно **обновлять** систему (unattended-upgrades)
|
- ✅ Регулярно **обновлять** систему (unattended-upgrades)
|
||||||
@ -715,9 +969,9 @@ pvesm update olimpbkp --password <новый_токен>
|
|||||||
| Проблема | Решение |
|
| Проблема | Решение |
|
||||||
|----------|---------|
|
|----------|---------|
|
||||||
| Не приходят уведомления | Проверить `curl -s https://api.telegram.org/bot<TOKEN>/getMe` |
|
| Не приходят уведомления | Проверить `curl -s https://api.telegram.org/bot<TOKEN>/getMe` |
|
||||||
| Реле не работает | `journalctl -u telegram-relay -n 20 --no-pager` |
|
| Ошибка iptables | Перезапустить `/usr/local/bin/telegram-proxy.sh` |
|
||||||
| XRay не запускается | `systemctl status xray-client` |
|
| XRay не запускается | `journalctl -u xray-client -n 20 --no-pager` |
|
||||||
| Дубликат уведомлений | Проверить Max Alerts в Contact Point |
|
| Дубликат уведомлений | Удалить `/var/run/pbs-notify-lastline` и пересоздать |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user