# 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-бот через Python-реле (порт 8085) |
### 📊 Архитектура
```mermaid
graph TD
A["Proxmox VE Host
Olimp 192.168.1.200"] --> B["LXC Containers
201-211"]
A --> C["Virtual Machines
205, 213"]
A -->|Network| D["Proxmox Backup Server
Olimpbs 192.168.1.199"]
D --> E["Datastore: olimpbkp
1 TB LVM"]
E --> F["/var/lib/proxmox-backup/olimpbkp"]
D -->|Python Relay 8085| G["Telegram API
api.telegram.org"]
G -->|SOCKS5 1080| H["XRay Proxy
2.27.50.20:2054"]
```
---
## Что бэкапится
### 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
```
### Проверка целостности (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 (через Python-реле)
### 🎯 Цель
Получать красивые уведомления в Telegram о статусе бэкапов с форматированием времени и эмодзи.
### 📋 Предварительные требования
- Сервер с доступом в интернет через прокси (XRay SOCKS5)
- Telegram бот: токен и chat_id
- Python 3 установлен
---
### 🔧 Настройка 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
backups = re.findall(r'"backup"\s*:\s*"([^"]+)"', body)
statuses = re.findall(r'"status"\s*:\s*"([^"]+)"', body)
values = re.findall(r'value=([\d.]+)', body)
if not backups:
client_socket.send(b"HTTP/1.1 200 OK\r\n\r\nOK")
return
# Отправляем порциями по 5 (чтобы влезло в лимит Telegram)
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)
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"▶ Relay on {PORT}", file=sys.stderr)
while True:
client, addr = server.accept()
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!
---
### 🔧 Настройка в Grafana (если используешь мониторинг)
**1. Contact Points → Add new:**
| Поле | Значение |
|------|----------|
| **Name** | `Telegram Relay` |
| **Type** | `Webhook` |
| **URL** | `http://192.168.1.208:8085` |
| **HTTP Method** | `POST` |
| **Max Alerts** | `0` (без лимита) |
**2. Сообщение (Message):**
```bash
{{ range .Alerts }}
📦 {{ .Labels.backup }}
⏱ {{ .Annotations.description }}
Status: {{ if eq .Status "firing" }}🔥{{ else }}✅{{ end }} {{ .Status }}
{{ end }}
```
**3. В Alert Rule → Annotations → Description:**
```bash
{{ .Value }}
```
*(Python-скрипт сам превратит секунды в "11 ч 35 мин")*
**4. Протестируй:**
- Contact Point → **Test**
- Должно прийти красивое уведомление
---
### 🔧 Настройка в Proxmox Backup Server (прямые уведомления)
Если хочешь уведомления напрямую из PBS (без Grafana):
**1. Создай endpoint (webhook):**
```bash
proxmox-backup-manager notification endpoint webhook create telegram \
--url "http://192.168.1.208:8085" \
--method post \
--header "Content-Type: application/json"
```
**2. Создай matcher для ошибок:**
```bash
proxmox-backup-manager notification matcher create backup-error \
--endpoint telegram \
--cal-filter backup \
--severity error
```
**3. Создай matcher для успехов (опционально):**
```bash
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` |
| `CHAT_ID` | ID чата для уведомлений | `292909723` |
| `PROXY` | SOCKS5 прокси (XRay) | `socks5://127.0.0.1:1080` |
| `PORT` | Порт реле (локальный) | `8085` |
| `GRAFANA_HOST` | IP сервера с Grafana | `192.168.1.208` |
---
### 📁 Файлы конфигурации
| Файл | Назначение |
|------|------------|
| `/usr/local/bin/telegram-relay.py` | Python-скрипт реле |
| `/etc/systemd/system/telegram-relay.service` | systemd-юнит |
| `/var/log/syslog` | Логи (через journalctl) |
---
### 🧪 Тестирование
**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
```
---
### 🔍 Troubleshooting
| Проблема | Решение |
|----------|---------|
| Не приходит сообщение | Проверь `journalctl -u telegram-relay -n 20` |
| Ошибка 400 от Telegram | Убери `parse_mode` или экранируй спецсимволы |
| Реле не слушает порт | `systemctl restart telegram-relay` |
| XRay не подключается | Проверь `systemctl status xray-client` |
| Сообщение обрезается | Скрипт разбивает на части по 5 бэкапов — это норма |
---
### 🎨 Формат уведомления
Пример того, что придёт в Telegram:
```mermaid
🚨 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** для доступа к PBS
- ✅ Создать **отдельного пользователя** для бэкапов (не 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/getMe` |
| Реле не работает | `journalctl -u telegram-relay -n 20 --no-pager` |
| XRay не запускается | `systemctl status xray-client` |
| Дубликат уведомлений | Проверить Max Alerts в Contact Point |
---
## Полезные команды
### На Proxmox VE
```bash
# Список хранилищ
pvesm list
# Статус бэкап хранилища
pvesm status olimpbkp
# Запустить бэкап
vzdump --storage olimpbkp --mode snapshot
# Восстановить
pct restore olimpbkp:backup/ct//
qm restore olimpbkp:backup/vm//
```
### На 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)