Docs/docs/11-backup.md
2026-04-13 17:26:31 +05:00

36 KiB
Raw Permalink Blame History

11. Резервное копирование

Обзор

Резервное копирование критически важно для защиты данных и возможности восстановления после сбоев, ошибок или атак.

Текущий статус (апрель 2026): Настроена полнофункциональная система резервного копирования на базе Proxmox Backup Server

  • Отдельный физический сервер PBS (192.168.1.199)
  • Хранилище 1 TB с дедупликацией и компрессией
  • Автоматические бэкапы всех критичных систем
  • Протестированное восстановление
  • Настроены уведомления в Telegram о статусе задач

Текущее состояние

Настроено и работает

Компонент Статус Описание
Proxmox Backup Server Отдельный сервер (Olimpbs, 192.168.1.199)
Хранилище 1 TB (LVM), datastore olimpbkp
Бэкапы ВМ/LXC Автоматические, по расписанию
Дедупликация Встроена в PBS
Компрессия ZSTD (fast and good)
Расписание 2 раза в день (02:30 и 22:30)
Retention 14 последних, 7 ежедневных, 4 недельных, 4 месячных
Режим Snapshot (без остановки сервисов)
Уведомления Telegram-бот через прокси (XRay + Redsocks)

📊 Архитектура

graph TD
    A["Proxmox VE Host<br/>Olimp 192.168.1.200"] --> B["LXC Containers<br/>201-211"]
    A --> C["Virtual Machines<br/>205, 213"]
    A -->|Network| D["Proxmox Backup Server<br/>Olimpbs 192.168.1.199"]
    D --> E["Datastore: olimpbkp<br/>1 TB LVM"]
    E --> F["/var/lib/proxmox-backup/olimpbkp"]
    D -->|HTTPS via proxy| G["Telegram API<br/>api.telegram.org"]

Что бэкапится

LXC Контейнеры (10 шт.)

ID Имя Тип данных Примерный размер
201 gateway Конфигурации, прокси ~5 GB
202 data Базы данных (BookStack, Mealie) ~10 GB
203 media Конфигурации Jellyfin, метаданные ~60 GB*
204 photo Immich конфиги ~20 GB
206 talk Matrix, XMPP конфиги ~10 GB
207 games Конфигурации игровых серверов ~20 GB
208 manage Grafana, Loki, мониторинг ~15 GB
209 git GitLab репозитории ~30 GB
210 ansible Ansible конфиги, vault ~5 GB
211 torrent qBittorrent настройки ~5 GB

*Без медиафайлов (исключены из бэкапа)

Виртуальные машины (2 шт.)

ID Имя Тип данных Примерный размер
205 Nextcloud Файлы, БД PostgreSQL ~10 GB
213 VPN OpenVPN/WireGuard конфиги ~12 GB

Исключено из бэкапа

  • Большие диски (16 TB RAID6): медиафайлы, игры, загрузки
  • Причина: занимают слишком много места, можно восстановить из источников
  • Что включено: только конфигурации и метаданные (через backup=1)

Расписание бэкапов

Автоматическое расписание

Два раза в день:

  • 02:30 — ночной бэкап
  • 22:30 — вечерний бэкап

Proxmox Backup Server автоматически определяет:

  • Первый бэкап — полный
  • Последующие — инкрементальные (только изменения)
  • Периодически — полный для целостности данных

Retention политика

Тип хранения Количество Фактический срок
Keep Last 14 Минимум 14 последних бэкапов
Keep Daily 7 7 ежедневных копий
Keep Weekly 4 4 недельных копии
Keep Monthly 4 4 месячных копии

Итого: ~1-2 месяца истории бэкапов


Текущая конфигурация

На Proxmox VE (Olimp)

Хранилище подключено:

  • ID: olimpbkp
  • Тип: Proxmox Backup Server
  • Server: 192.168.1.199:8007
  • Datastore: olimpbkp
  • Content: Backup
  • Status: Enabled

Backup Job:

Node: Olimp
Storage: olimpbkp
Schedule: 02:30, 22:30 (daily)
Mode: Snapshot
Compression: ZSTD
VM/CT: 201-211, 205, 213
Retention: keep-last=14, keep-daily=7, keep-weekly=4, keep-monthly=4

На PBS (Olimpbs)

Datastore:

Name: olimpbkp
Path: /var/lib/proxmox-backup/olimpbkp
Size: 1 TB (912 GB available)
GC Schedule: daily
Prune Schedule: daily

Пользователи:

  • root@pam — администратор (веб-интерфейс)
  • pve@pbs — для Proxmox VE (API токен)

Управление бэкапами

Просмотр бэкапов

Через веб-интерфейс PBS:

https://192.168.1.199:8007
  → Datastore → olimpbkp → Content

Через Proxmox VE:

https://192.168.1.220:8006
  → Datacenter → Storage → olimpbkp → Content

Через CLI:

# Список бэкапов
proxmox-backup-client list --repository root@pam@192.168.1.199:8007:olimpbkp

# Детальная информация
proxmox-backup-client show-backup --repository root@pam@192.168.1.199:8007:olimpbkp ct/201

# Статистика datastore
proxmox-backup-client datastore stats olimpbkp

Ручной запуск бэкапа

Один контейнер/ВМ:

vzdump 201 --storage olimpbkp --mode snapshot --compress zstd

Все бэкапируемые системы:

for id in 201 202 203 204 205 206 207 208 209 210 211 213; do
  vzdump $id --storage olimpbkp --mode snapshot --compress zstd &
done
wait

Восстановление из бэкапа

Через веб-интерфейс Proxmox VE:

  1. Datacenter → Storage → olimpbkp → Content
  2. Выбрать бэкап → Restore
  3. Указать:
    • Storage: целевое хранилище (local-lvm, vmsystem)
    • VMID: новый ID (или существующий для перезаписи)
  4. Start

Через CLI:

# LXC контейнер
pct restore 216 olimpbkp:backup/ct/201/2026-04-11T13:19:03Z --storage local-lvm

# Виртуальная машина
qm restore 216 olimpbkp:backup/vm/205/2026-04-11T13:19:03Z --storage vmsystem

Восстановление отдельных файлов

Через File Restore:

  1. PBS веб-интерфейс → Datastore → Content
  2. Выбрать бэкап → File Restore
  3. Смонтировать бэкап
  4. Скачать нужные файлы
  5. Unmount

Через CLI:

# Смонтировать бэкап
mkdir -p /mnt/restore
proxmox-backup-client mount ct/201/2026-04-11T13:19:03Z /mnt/restore \
  --repository root@pam@192.168.1.199:8007:olimpbkp

# Скопировать файлы
cp /mnt/restore/root.pxar/etc/config/file.conf /tmp/

# Размонтировать
proxmox-backup-client unmount /mnt/restore

Мониторинг и обслуживание

Проверка статуса бэкапов

Ежедневная проверка:

# Последние задачи
pvesm status olimpbkp

# Логи бэкапов
tail -f /var/log/pve/tasks/*

# Проверка места на PBS
ssh root@192.168.1.199 "df -h /var/lib/proxmox-backup/olimpbkp"

Garbage Collection (очистка)

PBS автоматически запускает GC ежедневно. Вручную:

# На PBS сервере
proxmox-backup-manager garbage-collection start olimpbkp

# Проверка статуса
proxmox-backup-manager garbage-collection status olimpbkp

Prune (удаление старых бэкапов)

Автоматически по retention политике. Вручную:

proxmox-backup-manager prune-job run <job-id>

Проверка целостности (Verify)

# Проверить все бэкапы
proxmox-backup-manager verify olimpbkp

# Проверить конкретный бэкап
proxmox-backup-client verify ct/201/2026-04-11T13:19:03Z \
  --repository root@pam@192.168.1.199:8007:olimpbkp

📦 Уведомления в 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 часов

📋 Предварительные требования

  • PBS сервер (192.168.1.199) с доступом в интернет через прокси
  • Telegram бот: токен и chat_id
  • Прокси: VLESS+Reality на 2.27.50.20:2054

🔧 Настройка прокси (XRay + Redsocks + iptables)

1. Установка XRay клиента

# Установка зависимостей
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

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 как сервис

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

# Установка
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

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. Проверка соединения

curl -s "https://api.telegram.org/bot<YOUR_BOT_TOKEN>/getMe"

Ожидаемый результат: JSON с информацией о боте.

🔧 Скрипт уведомлений

7. Создание скрипта

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 минут)

echo "*/5 * * * * root /usr/local/bin/pbs-backup-notify.sh" >> /etc/cron.d/pbs-notify

9. Инициализация и тест

# Сброс состояния для теста
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 с красивым форматированием, эмодзи и автоматическим преобразованием времени.

📋 Архитектура

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"]

🔧 Шаг 0: Установка XRay (если не установлен)

XRay нужен для проксирования запросов в Telegram.

1. Установи зависимости:

apt update && apt install unzip curl iptables -y

2. Скачай и установи 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

3. Создай конфигурацию:

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

4. Создай systemd-сервис:

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

5. Проверь работу:

systemctl status xray-client

# Тест соединения
curl -sx socks5://127.0.0.1:1080 \
  https://api.telegram.org/bot7657027552:AAHQ6OGDRbm6wtqh_4GOQr7jd6C0BAQMyF4/getMe

Должен вернуться JSON с информацией о боте.


🔧 Шаг 2: Установка Python-реле

1. Создай скрипт реле:

cat > /usr/local/bin/telegram-relay.py << 'EOF'
#!/usr/bin/env python3
import socket
import subprocess
import sys
import re

PORT = 8085
BOT_TOKEN = "7657027552:AAHQ6OGDRbm6wtqh_4GOQr7jd6C0BAQMyF4"
CHAT_ID = "292909723"
PROXY = "socks5://127.0.0.1:1080"

def format_duration(seconds):
    try:
        sec = float(seconds)
        if sec < 60:
            return f"{int(sec)} сек"
        elif sec < 3600:
            return f"{int(sec // 60)} мин"
        elif sec < 86400:
            hours = int(sec // 3600)
            mins = int((sec % 3600) // 60)
            return f"{hours} ч {mins} мин" if mins > 0 else f"{hours} ч"
        else:
            return f"{int(sec // 86400)} дн"
    except:
        return str(seconds)

def get_icon(backup):
    return "💻" if backup.startswith('vm-') else "📦" if backup.startswith('ct-') else "🗄️"

def send_telegram(text):
    try:
        cmd = [
            'curl', '-sx', PROXY, '-s',
            f'https://api.telegram.org/bot{BOT_TOKEN}/sendMessage',
            '-H', 'Content-Type: application/json',
            '-d', f'{{"chat_id":"{CHAT_ID}","text":"{text}","parse_mode":"Markdown"}}'
        ]
        subprocess.run(cmd, timeout=10, capture_output=True)
        return True
    except:
        return False

def handle_client(client_socket, addr):
    try:
        data = b""
        client_socket.settimeout(2)
        while True:
            try:
                chunk = client_socket.recv(4096)
                if not chunk:
                    break
                data += chunk
            except socket.timeout:
                break
        
        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
        
        # Парсим JSON от Grafana
        backups = re.findall(r'"backup"\s*:\s*"([^"]+)"', body)
        statuses = re.findall(r'"status"\s*:\s*"([^"]+)"', body)
        values = re.findall(r'value=([\d.]+)', body)
        
        # Если нашли бэкапы — форматируем как алерт
        if backups:
            CHUNK = 5
            for i in range(0, len(backups), CHUNK):
                chunk_backups = backups[i:i+CHUNK]
                text = "🚨 *Backup Alert*\n\n"
                
                for j, backup in enumerate(chunk_backups):
                    idx = i + j
                    status = statuses[idx] if idx < len(statuses) else "unknown"
                    icon = get_icon(backup)
                    
                    if len(values) >= (idx * 2 + 1):
                        seconds = float(values[idx * 2])
                        human_time = format_duration(seconds)
                        desc = f"Последний бэкап: {human_time} назад"
                    else:
                        desc = "Нет данных"
                    
                    status_emoji = "🔥" if status == "firing" else "✅"
                    text += f"{icon} *{backup}*\n⏱ {desc}\nStatus: {status_emoji} *{status}*\n\n"
                
                send_telegram(text)
        else:
            # Если не JSON от Grafana — отправляем как есть (для тестов)
            # Очищаем от служебных символов
            clean_text = body.strip().replace('\r', '').replace('\n', ' ')
            if clean_text and len(clean_text) < 4000:
                send_telegram(clean_text)
        
        client_socket.send(b"HTTP/1.1 200 OK\r\nContent-Length: 2\r\nConnection: close\r\n\r\nOK")
        
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        try:
            client_socket.send(b"HTTP/1.1 500 Error\r\n\r\n")
        except:
            pass
    finally:
        try:
            client_socket.close()
        except:
            pass

# Запуск сервера
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(('0.0.0.0', PORT))
server.listen(10)
print(f"▶ Telegram Relay on {PORT}", file=sys.stderr)

while True:
    client, addr = server.accept()
    print(f"← {addr}", file=sys.stderr)
    handle_client(client, addr)
EOF
chmod +x /usr/local/bin/telegram-relay.py

2. Создай systemd-сервис:

cat > /etc/systemd/system/telegram-relay.service << 'EOF'
[Unit]
Description=Telegram Relay via Xray (Python+curl)
After=network.target xray-client.service
Requires=xray-client.service

[Service]
Type=simple
ExecStart=/usr/bin/python3 /usr/local/bin/telegram-relay.py
Restart=always
RestartSec=3
User=root
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now telegram-relay

3. Проверь работу:

# Проверка статуса
systemctl status telegram-relay

# Проверка порта
ss -tlnp | grep 8085

# Тест
curl -X POST http://127.0.0.1:8085 -d "🎉 Test message"

Должно прийти сообщение в Telegram!


🔧 Шаг 2: Настройка Contact Point в Grafana

1. Открой Grafana:

  • Перейди: AlertingContact points
  • Нажми + Add contact point

2. Заполни поля:

Поле Значение
Name Telegram Relay
Integration Webhook
URL http://127.0.0.1:8085
HTTP Method POST
Max Alerts 0 (без лимита)

3. Сообщение (Message):

{{ range .Alerts }}
📦 {{ .Labels.backup }}
⏱ {{ .Annotations.description }}
Status: {{ if eq .Status "firing" }}🔥{{ else }}✅{{ end }} {{ .Status }}
---
{{ end }}

4. Сохрани:

  • Нажми Save contact point
  • Нажми Test — должно прийти сообщение

🔧 Шаг 3: Создание Alert Rule

1. Перейди: AlertingAlert 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:

{{ .Value }}

(Python-скрипт сам превратит секунды в "11 ч 35 мин")

4. Notifications:

  • Выбери Contact Point: Telegram Relay

5. Сохрани правило


🔧 Шаг 4: Проверка

1. Проверка реле:

# Логи реле
journalctl -u telegram-relay -f

# Тестовый запрос
curl -X POST http://127.0.0.1:8085 \
  -H "Content-Type: application/json" \
  -d '{"text":"✅ Grafana relay test"}'

2. Проверка XRay:

# Статус XRay
systemctl status xray-client

# Тест соединения с Telegram
curl -sx socks5://127.0.0.1:1080 \
  https://api.telegram.org/bot7657027552:AAHQ6OGDRbm6wtqh_4GOQr7jd6C0BAQMyF4/getMe

3. Тест алерта:

  • В Grafana: Contact Point → Test
  • Должно прийти сообщение в Telegram

📝 Переменные для замены

Переменная Описание Значение
BOT_TOKEN Токен Telegram бота 7657027552:AAHQ6OGDRbm6wtqh_4GOQr7jd6C0BAQMyF4
CHAT_ID ID чата для уведомлений 292909723
PROXY SOCKS5 прокси socks5://127.0.0.1:1080
PORT Порт реле 8085

📁 Файлы конфигурации

Файл Назначение
/usr/local/bin/telegram-relay.py Python-скрипт реле
/etc/systemd/system/telegram-relay.service systemd-юнит
/etc/grafana/provisioning/alerting/ Конфиги алертов Grafana

🔍 Troubleshooting

Проблема Решение
Не приходит сообщение journalctl -u telegram-relay -n 20
Ошибка 400 от Telegram Убери parse_mode или экранируй спецсимволы
Реле не слушает порт systemctl restart telegram-relay
XRay не подключается systemctl status xray-client
Сообщение обрезается Скрипт разбивает на части по 5 бэкапов — это норма
Grafana не шлёт Проверь что Alert Rule в состоянии "Firing"

🎨 Пример уведомления

🚨 Backup Alert

📦 ct-201
⏱ Последний бэкап: 11 ч 35 мин назад
Status: 🔥 firing

📦 ct-202
⏱ Последний бэкап: 11 ч 34 мин назад
Status: 🔥 firing

💻 vm-205
⏱ Последний бэкап: 11 ч 30 мин назад
Status: ✅ resolved

Эмодзи:

  • 💻 — виртуальные машины (vm-*)
  • 📦 — LXC контейнеры (ct-*)
  • 🔥 — статус firing (проблема)
  • — статус resolved (всё ок)

🔄 Обновление скрипта

# Останови сервис
systemctl stop telegram-relay

# Отредактируй скрипт
nano /usr/local/bin/telegram-relay.py

# Запусти снова
systemctl start telegram-relay

# Проверь статус
systemctl status telegram-relay

Безопасность

Аутентификация

  • PBS пользователи: root@pam, pve@pbs
  • API токены: для автоматизации (без паролей)
  • Fingerprint: SHA-256 отпечаток сертификата

Сетевая безопасность

  • Порт: 8007 (TCP)
  • Шифрование: TLS 1.3
  • Доступ: только из локальной сети (192.168.1.0/24)

Рекомендации

  • Включить 2FA для root@pam
  • Создать отдельного пользователя для бэкапов (не root)
  • Настроить firewall на PBS сервере
  • Регулярно обновлять систему (unattended-upgrades)

Планы на будущее

🔵 Краткосрочные (1-2 месяца)

  • Настроить уведомления (Telegram) о статусе бэкапов
  • Включить 2FA для доступа к PBS
  • Настроить репликацию в облако (Backblaze B2 / Wasabi)
  • Провести тестовое восстановление всех критичных ВМ

🔵 Долгосрочные (3-6 месяцев)

  • Добавить второй PBS для репликации
  • Настроить оффсайт-копии (внешний диск + облако)
  • Внедрить шифрование бэкапов на стороне клиента
  • Автоматизировать тестирование восстановления

Troubleshooting

Бэкап не запускается

# Проверить хранилище
pvesm status | grep olimpbkp

# Проверить подключение к PBS
ping 192.168.1.199
nc -zv 192.168.1.199 8007

# Переподключить хранилище
pvesm remove olimpbkp
pvesm add proxmox-backup olimpbkp \
  --server 192.168.1.199 \
  --datastore olimpbkp \
  --username pve@pbs

Закончилось место на PBS

# Проверить занятое место
proxmox-backup-client datastore stats olimpbkp

# Запустить GC
proxmox-backup-manager garbage-collection start olimpbkp

# Удалить старые бэкапы вручную
proxmox-backup-client prune \
  --repository root@pam@192.168.1.199:8007:olimpbkp \
  --max-daily 7 --max-weekly 2

Ошибка аутентификации PBS

# Сгенерировать новый токен
proxmox-backup-manager user generate-token pve@pbs backup-token

# Обновить в Proxmox VE
pvesm update olimpbkp --password <новый_токен>

Проблемы с уведомлениями в Telegram

Проблема Решение
Не приходят уведомления Проверить curl -s https://api.telegram.org/bot<TOKEN>/getMe
Ошибка iptables Перезапустить /usr/local/bin/telegram-proxy.sh
XRay не запускается journalctl -u xray-client -n 20 --no-pager
Дубликат уведомлений Удалить /var/run/pbs-notify-lastline и пересоздать

Полезные команды

На Proxmox VE

# Список хранилищ
pvesm list

# Статус бэкап хранилища
pvesm status olimpbkp

# Запустить бэкап
vzdump <vmid> --storage olimpbkp --mode snapshot

# Восстановить
pct restore <new-vmid> olimpbkp:backup/ct/<ctid>/<timestamp>
qm restore <new-vmid> olimpbkp:backup/vm/<vmid>/<timestamp>

На PBS

# Список datastore
proxmox-backup-manager datastore list

# Статистика
proxmox-backup-client datastore stats olimpbkp

# Список бэкапов
proxmox-backup-client list --repository root@pam@192.168.1.199:8007:olimpbkp

# Информация о бэкапе
proxmox-backup-client show-backup ct/201 --repository root@pam@192.168.1.199:8007:olimpbkp

# Проверка целостности
proxmox-backup-manager verify olimpbkp

# Garbage collection
proxmox-backup-manager garbage-collection start olimpbkp

Метрики и отчётность

Ежедневная проверка

# Размер бэкапов за сегодня
du -sh /var/lib/proxmox-backup/olimpbkp/data/*

# Количество бэкапов
proxmox-backup-client list --repository root@pam@192.168.1.199:8007:olimpbkp | wc -l

# Свободное место
df -h /var/lib/proxmox-backup/olimpbkp

Еженедельный отчёт

# Дедупликация
proxmox-backup-client datastore stats olimpbkp | grep "Deduplication"

# Прирост за неделю
# Сравнить размер datastore с прошлой неделей

Связанные разделы: