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

1159 lines
36 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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) |
### 📊 Архитектура
```mermaid
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**:
```text
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**:
```text
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**:
```text
https://192.168.1.199:8007
→ Datastore → olimpbkp → Content
```
**Через Proxmox VE**:
```text
https://192.168.1.220:8006
→ Datacenter → Storage → olimpbkp → Content
```
**Через CLI**:
```bash
# Список бэкапов
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
```
### Ручной запуск бэкапа
**Один контейнер/ВМ**:
```bash
vzdump 201 --storage olimpbkp --mode snapshot --compress zstd
```
**Все бэкапируемые системы**:
```bash
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**:
```bash
# 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**:
```bash
# Смонтировать бэкап
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
```
---
## Мониторинг и обслуживание
### Проверка статуса бэкапов
**Ежедневная проверка**:
```bash
# Последние задачи
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 ежедневно. Вручную:
```bash
# На PBS сервере
proxmox-backup-manager garbage-collection start olimpbkp
# Проверка статуса
proxmox-backup-manager garbage-collection status olimpbkp
```
### Prune (удаление старых бэкапов)
Автоматически по retention политике. Вручную:
```bash
proxmox-backup-manager prune-job run <job-id>
```
### Проверка целостности (Verify)
```bash
# Проверить все бэкапы
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 клиента**
```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"]
```
---
### 🔧 Шаг 0: Установка XRay (если не установлен)
**XRay нужен для проксирования запросов в Telegram.**
**1. Установи зависимости:**
```bash
apt update && apt install unzip curl iptables -y
```
**2. Скачай и установи XRay:**
```bash
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. Создай конфигурацию:**
```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
```
**4. Создай systemd-сервис:**
```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
```
**5. Проверь работу:**
```bash
systemctl status xray-client
# Тест соединения
curl -sx socks5://127.0.0.1:1080 \
https://api.telegram.org/bot7657027552:AAHQ6OGDRbm6wtqh_4GOQr7jd6C0BAQMyF4/getMe
```
Должен вернуться JSON с информацией о боте.
---
### 🔧 Шаг 2: Установка Python-реле
**1. Создай скрипт реле:**
```bash
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-сервис:**
```bash
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. Проверь работу:**
```bash
# Проверка статуса
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:**
- Перейди: **Alerting****Contact 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):**
```text
{{ range .Alerts }}
📦 {{ .Labels.backup }}
⏱ {{ .Annotations.description }}
Status: {{ if eq .Status "firing" }}🔥{{ else }}✅{{ end }} {{ .Status }}
---
{{ end }}
```
**4. Сохрани:**
- Нажми **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 }}
```
*(Python-скрипт сам превратит секунды в "11 ч 35 мин")*
**4. Notifications:**
- Выбери Contact Point: `Telegram Relay`
**5. Сохрани правило**
---
### 🔧 Шаг 4: Проверка
**1. Проверка реле:**
```bash
# Логи реле
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:**
```bash
# Статус 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" |
---
### 🎨 Пример уведомления
```text
🚨 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 (всё ок)
---
### 🔄 Обновление скрипта
```bash
# Останови сервис
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 месяца)
- [x] Настроить **уведомления** (Telegram) о статусе бэкапов
- [ ] Включить **2FA** для доступа к PBS
- [ ] Настроить **репликацию** в облако (Backblaze B2 / Wasabi)
- [ ] Провести **тестовое восстановление** всех критичных ВМ
### 🔵 Долгосрочные (3-6 месяцев)
- [ ] Добавить **второй PBS** для репликации
- [ ] Настроить **оффсайт-копии** (внешний диск + облако)
- [ ] Внедрить **шифрование** бэкапов на стороне клиента
- [ ] Автоматизировать **тестирование восстановления**
---
## Troubleshooting
### Бэкап не запускается
```bash
# Проверить хранилище
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
```bash
# Проверить занятое место
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
```bash
# Сгенерировать новый токен
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
```bash
# Список хранилищ
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
```bash
# Список 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
```
---
## Метрики и отчётность
### Ежедневная проверка
```bash
# Размер бэкапов за сегодня
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
```
### Еженедельный отчёт
```bash
# Дедупликация
proxmox-backup-client datastore stats olimpbkp | grep "Deduplication"
# Прирост за неделю
# Сравнить размер datastore с прошлой неделей
```
---
**Связанные разделы:**
- [Гипервизор Proxmox](02-hypervisor.md)
- [Виртуальные машины и LXC](03-vms-lxcs.md)
- [Безопасность](10-security.md)
- [Мониторинг и логирование](08-monitoring.md)