Add notification feature to backup scripts for various services

Enhance backup scripts for Nextcloud, Gitea, Paperless, Vaultwarden, Immich, and VPS configurations by adding Telegram notifications upon completion. Include details such as backup size and objects backed up. Update backup documentation to reflect these changes and ensure clarity on backup processes and retention policies.
This commit is contained in:
2026-02-27 20:42:30 +03:00
parent 56cee83198
commit f319133cee
21 changed files with 1048 additions and 168 deletions

View File

@@ -33,23 +33,24 @@
## Что, откуда, куда, когда
| Что | Откуда | Куда (локально) | Когда | Хранение |
|-----|--------|------------------|------|----------|
| **LXC и VM** | Все выбранные контейнеры (100109) и VM 200 | `/mnt/backup/proxmox/dump/` | **02:00** ежедневно (задание в Proxmox UI) | По настройкам задания (например: 7 daily, 4 weekly, 6 monthly) |
| **Конфиги хоста** | `/etc/pve`, `/etc/network/interfaces`, `/etc/hosts`, `/etc/resolv.conf` | `/mnt/backup/proxmox/etc-pve/` | **02:15** ежедневно (cron: `backup-etc-pve.sh`) | 30 дней |
| **БД Nextcloud (PostgreSQL)** | CT 101, контейнер `nextcloud-db-1` в `/opt/nextcloud` | `/mnt/backup/databases/ct101-nextcloud/` | **01:15** ежедневно (cron: `backup-ct101-pgdump.sh`) | 14 дней |
| **БД Gitea (PostgreSQL)** | CT 103, контейнер `gitea-db-1` в `/opt/gitea` | `/mnt/backup/databases/ct103-gitea/` | **03:00** ежедневно (cron: `backup-ct103-gitea-pgdump.sh`) | 14 дней |
| **БД Paperless (PostgreSQL)** | CT 104, контейнер `paperless-db-1` в `/opt/paperless` | `/mnt/backup/databases/ct104-paperless/` | **02:30** ежедневно (cron: `backup-ct104-pgdump.sh`) | 14 дней |
| **Данные Vaultwarden (пароли)** | CT 103, `/opt/docker/vaultwarden/data` | `/mnt/backup/other/vaultwarden/` | **02:45** ежедневно (cron: `backup-vaultwarden-data.sh`); каталог в restic → Yandex | 14 дней |
| **БД Immich (PostgreSQL)** | VM 200, контейнер `database` в `/opt/immich` | `/mnt/backup/databases/vm200-immich/` | **03:15** ежедневно (cron: `backup-vm200-pgdump.sh`) | 14 дней |
| **Векторы RAG (CT 105)** | CT 105, `/home/rag-service/data/vectors/` (vectors.npz) | `/mnt/backup/other/ct105-vectors/` | **03:30** ежедневно (cron: `backup-ct105-vectors.sh`) | 14 дней |
| **Оригиналы фото Immich** | VM 200, `/mnt/data/library/` | `/mnt/backup/photos/library/` | **01:30** ежедневно (cron: `backup-immich-photos.sh`, rsync) | Все копии (без автоудаления) |
| **VPS Миран (telegram-helper-bot)** | VPS 185.147.80.190: БД `tg-bot-database.db`, каталог `voice_users`, бакет S3 (Miran) | `/mnt/backup/vps/miran/` (db/, voice_users/, s3/) | **01:00** ежедневно (cron: `backup-vps-miran.sh`) | БД: 14 дней; voice_users и S3 — перезапись |
| **Конфиги MTProto (VPS Германия)** | VPS 185.103.253.99: mtg.service, nginx (katykhin.store), Let's Encrypt, `/var/www/katykhin.store` | `/mnt/backup/vps/mtproto-germany/` (архивы mtproto-config-*.tar.gz) | **01:45** ежедневно (cron: `backup-vps-mtproto.sh`) | 14 дней |
| **Выгрузка в Yandex (restic)** | `/mnt/backup` без photos | Yandex Object Storage | **04:00** ежедневно (cron: `backup-restic-yandex.sh`) | 3 daily, 2 weekly, 2 monthly |
| **Выгрузка в Yandex (restic, фото)** | `/mnt/backup/photos` | Yandex Object Storage (тот же репо) | **01:00** ежедневно (cron: `backup-restic-yandex-photos.sh`) | 3 daily, 2 weekly, 2 monthly |
**Окно бэкапов:** внутренние копии (синк внутри сервера) — **01:0003:30**; выгрузка в облако — **04:00**. **05:00** зарезервировано под плановую перезагрузку сервера. Задание vzdump — из веб-интерфейса Proxmox (Центр обработки данных → Резервная копия).
| Что | Откуда | Куда (локально) | Когда | Хранение | Уведомление |
|-----|--------|------------------|------|----------|--------------|
| **VPS Миран (telegram-helper-bot)** | VPS 185.147.80.190: БД `tg-bot-database.db`, каталог `voice_users`, бакет S3 (Miran) | `/mnt/backup/vps/miran/` (db/, voice_users/, s3/) | **01:00** (cron: `backup-vps-miran.sh`) | БД: 14 дней; voice_users и S3 — перезапись | 🖥️ VPS Миран |
| **БД Nextcloud (PostgreSQL)** | CT 101, контейнер `nextcloud-db-1` в `/opt/nextcloud` | `/mnt/backup/databases/ct101-nextcloud/` | **01:15** (cron: `backup-ct101-pgdump.sh`) | 14 дней | 🗄️ Nextcloud (БД) |
| **Оригиналы фото Immich** | VM 200, `/mnt/data/library/` | `/mnt/backup/photos/library/` | **01:30** (cron: `backup-immich-photos.sh`, rsync) | Все копии (без автоудаления) | 📷 Фото Immich (rsync) |
| **Конфиги MTProto (VPS Германия)** | VPS 185.103.253.99: mtg.service, nginx (katykhin.store), Let's Encrypt, `/var/www/katykhin.store` | `/mnt/backup/vps/mtproto-germany/` (архивы mtproto-config-*.tar.gz) | **01:45** (cron: `backup-vps-mtproto.sh`) | 14 дней | 🌐 VPS MTProto (DE) |
| **LXC и VM** | Все выбранные контейнеры (100109) и VM 200 | `/mnt/backup/proxmox/dump/` | **02:00** (задание в Proxmox UI) | По настройкам задания (7 daily, 4 weekly, 6 monthly) | 💾 Backup local (cron 03:00) |
| **Конфиги хоста** | `/etc/pve`, `/etc/network/interfaces`, `/etc/hosts`, `/etc/resolv.conf` | `/mnt/backup/proxmox/etc-pve/` | **02:15** (cron: `backup-etc-pve.sh`) | 30 дней | ⚙️ Конфиги хоста |
| **БД Paperless (PostgreSQL)** | CT 104, контейнер `paperless-db-1` в `/opt/paperless` | `/mnt/backup/databases/ct104-paperless/` | **02:30** (cron: `backup-ct104-pgdump.sh`) | 14 дней | 🗄️ Paperless (БД) |
| **Данные Vaultwarden (пароли)** | CT 103, `/opt/docker/vaultwarden/data` | `/mnt/backup/other/vaultwarden/`; каталог в restic → Yandex | **02:45** (cron: `backup-vaultwarden-data.sh`) | 14 дней | 🔐 Vaultwarden |
| **БД Gitea (PostgreSQL)** | CT 103, контейнер `gitea-db-1` в `/opt/gitea` | `/mnt/backup/databases/ct103-gitea/` | **03:00** (cron: `backup-ct103-gitea-pgdump.sh`) | 14 дней | 🗄️ Gitea (БД) |
| **БД Immich (PostgreSQL)** | VM 200, контейнер `database` в `/opt/immich` | `/mnt/backup/databases/vm200-immich/` | **03:15** (cron: `backup-vm200-pgdump.sh`) | 14 дней | 🗄️ Immich (БД) |
| **Векторы RAG (CT 105)** | CT 105, `/home/rag-service/data/vectors/` (vectors.npz) | `/mnt/backup/other/ct105-vectors/` | **03:30** (cron: `backup-ct105-vectors.sh`) | 14 дней | 📐 Векторы RAG |
| **Выгрузка в Yandex (restic)** | `/mnt/backup` без photos | Yandex Object Storage | **04:00** (cron: `backup-restic-yandex.sh`) | 3 daily, 2 weekly, 2 monthly | ☁️ Restic Yandex |
| **Выгрузка в Yandex (restic, фото)** | `/mnt/backup/photos` | Yandex Object Storage (тот же репо) | **04:10** (cron: `backup-restic-yandex-photos.sh`) | 3 daily, 2 weekly, 2 monthly | 📷 Restic Yandex (photos) |
**Окно бэкапов:** внутренние копии — **01:0003:30**; выгрузка в облако — **04:00** (основной restic), **04:10** (restic фото). **05:00** зарезервировано под плановую перезагрузку сервера. Задание vzdump — из веб-интерфейса Proxmox (Центр обработки данных → Резервная копия).
---
@@ -76,7 +77,6 @@
pct create 999 /mnt/backup/proxmox/dump/dump/vzdump-lxc-107-2026_02_26-02_03_14.tar.zst --restore 1 --storage local-lvm
```
Если восстанавливаем поверх существующего контейнера: сначала удалить его (`pct destroy 107`), затем в команде указать тот же VMID (107). Доп. опции: `pct create --help` (режим restore).
- **VM (KVM)** — порядок аргументов: сначала архив, потом VMID:
```bash
qm restore /mnt/backup/proxmox/dump/dump/vzdump-qemu-200-YYYY_MM_DD-HH_MM_SS.vma.zst 200 --storage local-lvm
@@ -86,7 +86,7 @@
**После восстановления (пример для LXC):**
- Если восстановили в новый слот (например 999) и не нужен конфликт IP с оригиналом — сменить IP:
`pct set 999 --net0 name=eth0,bridge=vmbr0,gw=192.168.1.1,ip=192.168.1.199/24,type=veth`
`pct set 999 --net0 name=eth0,bridge=vmbr0,gw=192.168.1.1,ip=192.168.1.199/24,type=veth`
- Запуск: `pct start 999` (LXC) или `qm start 200` (VM).
- Проверка: пинг, консоль (`pct exec 999 -- bash`), при необходимости сервисы и порты внутри контейнера.
@@ -99,17 +99,17 @@
**Когда нужно:** переустановка Proxmox или потеря конфигов узла (при этом диск с бэкапами доступен).
Если конфигов нет локально, но есть в Yandex — см. раздел **Восстановление из restic** → «Восстановление конфигов хоста (/etc/pve)».
1. Скопировать нужный архив с хоста, например:
`etc-pve-YYYYMMDD-HHMM.tar.gz` и/или `etc-host-configs-YYYYMMDD-HHMM.tar.gz` из `/mnt/backup/proxmox/etc-pve/`.
1. Скопировать нужный архив с хоста, например:
`etc-pve-YYYYMMDD-HHMM.tar.gz` и/или `etc-host-configs-YYYYMMDD-HHMM.tar.gz` из `/mnt/backup/proxmox/etc-pve/`.
2. **Восстановление /etc/pve** (на переустановленном хосте, от root):
```bash
```bash
tar -xzf etc-pve-YYYYMMDD-HHMM.tar.gz -C /
```
```
При одномузловой установке обычно достаточно распаковать в `/`. При кластере — аккуратно с нодами и storage.
3. **Восстановление конфигов сети/хоста** (interfaces, hosts, resolv.conf):
```bash
```bash
tar -xzf etc-host-configs-YYYYMMDD-HHMM.tar.gz -C /
```
```
При необходимости поправить под текущее железо (интерфейсы, IP) и перезапустить сеть.
После восстановления конфигов — заново добавить storage для бэкапов (если переустанавливали с нуля) и восстанавливать гостей из vzdump по шагу 1.
@@ -120,17 +120,14 @@
**Когда нужно:** повреждение или потеря базы Immich при рабочей ВМ (образ VM можно не трогать, восстанавливаем только БД).
1. Скопировать нужный дамп на VM 200, например:
`immich-db-YYYYMMDD-HHMM.sql.gz` из `/mnt/backup/databases/vm200-immich/`.
2. На VM 200 (ssh admin@192.168.1.200):
```bash
1. Скопировать нужный дамп на VM 200, например:
`immich-db-YYYYMMDD-HHMM.sql.gz` из `/mnt/backup/databases/vm200-immich/`.
2. На VM 200 (ssh [admin@192.168.1.200](mailto:admin@192.168.1.200)):
```bash
cd /opt/immich
gunzip -c /path/to/immich-db-YYYYMMDD-HHMM.sql.gz | docker compose exec -T database psql -U <DB_USERNAME> -d <DB_DATABASE_NAME>
```
```
Или распаковать `.sql.gz`, затем:
```bash
docker compose exec -T database psql -U <DB_USERNAME> -d <DB_DATABASE_NAME> < backup.sql
```
`<DB_USERNAME>` и `<DB_DATABASE_NAME>` — из `/opt/immich/.env` (обычно `postgres` и `immich`).
Перед восстановлением лучше остановить приложение Immich (или как минимум не писать в БД). При полной пересоздании БД — очистить каталог данных PostgreSQL в контейнере и затем загрузить дамп.
@@ -178,18 +175,20 @@ rsync -av /mnt/backup/photos/library/ admin@192.168.1.200:/mnt/data/library/
**Когда нужно:** потеря данных на VPS или перенос бота на другой хост.
В бэкапе есть:
- **БД:** `/mnt/backup/vps/miran/db/tg-bot-database-YYYYMMDD.db` — копии SQLite.
- **Голосовые сообщения:** `/mnt/backup/vps/miran/voice_users/` — каталог .ogg.
- **S3 (контент бота):** `/mnt/backup/vps/miran/s3/` — полная копия бакета (photos, videos, voice и т.д.).
**Восстановление на VPS:**
1. Скопировать выбранный файл БД на VPS:
`scp -P 15722 /mnt/backup/vps/miran/db/tg-bot-database-YYYYMMDD.db deploy@185.147.80.190:/home/prod/bots/telegram-helper-bot/database/tg-bot-database.db`
2. Восстановить `voice_users`:
`rsync -avz -e "ssh -p 15722" /mnt/backup/vps/miran/voice_users/ deploy@185.147.80.190:/home/prod/bots/telegram-helper-bot/voice_users/`
1. Скопировать выбранный файл БД на VPS:
`scp -P 15722 /mnt/backup/vps/miran/db/tg-bot-database-YYYYMMDD.db deploy@185.147.80.190:/home/prod/bots/telegram-helper-bot/database/tg-bot-database.db`
2. Восстановить `voice_users`:
`rsync -avz -e "ssh -p 15722" /mnt/backup/vps/miran/voice_users/ deploy@185.147.80.190:/home/prod/bots/telegram-helper-bot/voice_users/`
3. При потере данных в S3 — загрузить из бэкапа в бакет Miran (через aws s3 sync или панель), используя endpoint `https://api.s3.miran.ru` и креды из [VPS Миран](vps-miran-bots.md).
**Требования для бэкапа:** на хосте Proxmox — SSH-ключ root → deploy@185.147.80.190 (порт 15722); для S3 — установленный `aws` cli и файл `/root/.vps-miran-s3.env` с переменными S3_ACCESS_KEY, S3_SECRET_KEY, S3_BUCKET_NAME (см. [VPS Миран](../vps/vps-miran-bots.md)).
**Требования для бэкапа:** на хосте Proxmox — SSH-ключ root → [deploy@185.147.80.190](mailto:deploy@185.147.80.190) (порт 15722); для S3 — установленный `aws` cli и файл `/root/.vps-miran-s3.env` с переменными S3_ACCESS_KEY, S3_SECRET_KEY, S3_BUCKET_NAME (см. [VPS Миран](../vps/vps-miran-bots.md)).
---
@@ -198,19 +197,22 @@ rsync -av /mnt/backup/photos/library/ admin@192.168.1.200:/mnt/data/library/
**Когда нужно:** потеря конфигов на VPS 185.103.253.99 или перенос MTProto и сайта-заглушки на другой хост.
В архиве `mtproto-config-YYYYMMDD-HHMM.tar.gz` из `/mnt/backup/vps/mtproto-germany/` лежат:
- **mtg:** `etc/systemd/system/mtg.service` (в т.ч. секрет и cloak-port).
- **nginx:** `etc/nginx/sites-available/`, `etc/nginx/sites-enabled/` (конфиг для katykhin.store на порту 993).
- **Let's Encrypt:** `etc/letsencrypt/live/katykhin.store/`, `archive/katykhin.store/`, `renewal/katykhin.store.conf`.
- **Сайт:** `var/www/katykhin.store/`.
**Восстановление на VPS (от root):** скопировать архив на сервер и распаковать в корень:
```bash
scp /mnt/backup/vps/mtproto-germany/mtproto-config-YYYYMMDD-HHMM.tar.gz root@185.103.253.99:/tmp/
ssh root@185.103.253.99 "tar -xzf /tmp/mtproto-config-YYYYMMDD-HHMM.tar.gz -C /"
```
После распаковки: `systemctl daemon-reload && systemctl restart mtg nginx`. На новом хосте дополнительно установить mtg, nginx, certbot и настроить ufw (см. [план MTProto + сайт](../vps/vpn-vps-mtproto-site-plan.md)).
**Требования для бэкапа:** на хосте Proxmox — SSH по ключу root → root@185.103.253.99 (порт 22). Ключ хоста должен быть добавлен в `authorized_keys` на VPS.
**Требования для бэкапа:** на хосте Proxmox — SSH по ключу root → [root@185.103.253.99](mailto:root@185.103.253.99) (порт 22). Ключ хоста должен быть добавлен в `authorized_keys` на VPS.
---
@@ -225,14 +227,16 @@ ssh root@185.103.253.99 "tar -xzf /tmp/mtproto-config-YYYYMMDD-HHMM.tar.gz -C /"
VM 200 **не входит** в задание vzdump (образ ~380 ГБ, не помещается в политику 7 копий). В бэкапе есть: **конфиг ВМ** (в архивах `/etc/pve`), **БД** (pg_dump), **фото** (rsync в `photos/library`). Восстановление — создание новой ВМ с теми же параметрами и перенос данных.
**Что есть после восстановления хоста:**
- Из бэкапа `etc-pve`: файл `/etc/pve/qemu-server/200.conf` — полное описание ВМ (CPU, память, диски, **hostpci для GPU**, сеть). Его можно использовать как образец при создании новой ВМ.
- Дамп БД: `/mnt/backup/databases/vm200-immich/immich-db-*.sql.gz`.
- Фото: `/mnt/backup/photos/library/`.
**Ключевые параметры VM 200** (если восстанавливать вручную без конфига):
- **Ресурсы:** 3 ядра, 10 GB RAM.
- **GPU:** проброс видеокарты (hostpci) — в Proxmox: Hardware → Add → PCI Device → выбрать VGA/NVIDIA, поставить «All Functions» и «ROM-Bar» при необходимости. В конфиге это выглядит как `hostpci0: 0000:xx:00.0` и т.п.
- **Диски:** первый — системный (~35 GB), второй — данные (~350 GB) под `/mnt/data` (библиотека, PostgreSQL, Docker).
- **Диски:** первый — системный (~~35 GB), второй — данные (~~350 GB) под `/mnt/data` (библиотека, PostgreSQL, Docker).
- **Сеть:** статический IP 192.168.1.200/24, шлюз 192.168.1.1.
- **ОС:** Debian 13 (trixie), пользователь **admin**, SSH.
@@ -243,8 +247,8 @@ VM 200 **не входит** в задание vzdump (образ ~380 ГБ, н
3. **Разметить второй диск** и смонтировать в `/mnt/data` (как в [container-200](../containers/container-200.md)).
4. **Установить Docker**, склонировать/восстановить каталоги Immich: `/opt/immich/` (docker-compose.yml, .env — из своих заметок или копии; секреты из Vaultwarden).
5. **Создать каталоги** `/mnt/data/library`, `/mnt/data/postgres` (и др. по .env).
6. **Скопировать фото** с хоста бэкапов на ВМ:
`rsync -av /mnt/backup/photos/library/ admin@192.168.1.200:/mnt/data/library/`
6. **Скопировать фото** с хоста бэкапов на ВМ:
`rsync -av /mnt/backup/photos/library/ admin@192.168.1.200:/mnt/data/library/`
7. **Запустить только контейнер БД** (database), восстановить дамп (см. раздел 3 выше), затем поднять весь стек Immich.
8. Проверить NPM (прокси на 192.168.1.200:2283), при необходимости заново включить ML и настройки в Immich.
@@ -254,7 +258,7 @@ VM 200 **не входит** в задание vzdump (образ ~380 ГБ, н
## Restic и Yandex
Два задания в одном репозитории: **`backup-restic-yandex.sh`** выгружает `/mnt/backup` **без** каталога `photos`; **`backup-restic-yandex-photos.sh`** выгружает только `/mnt/backup/photos` (отдельный снимок, больше всего данных). Retention у обоих: **3 daily, 2 weekly, 2 monthly**. Пароли и дампы — чувствительные данные; не выкладывать в открытый доступ.
Два задания в одном репозитории: `**backup-restic-yandex.sh`** выгружает `/mnt/backup` **без** каталога `photos`; `**backup-restic-yandex-photos.sh`** выгружает только `/mnt/backup/photos` (отдельный снимок, больше всего данных). Retention у обоих: **3 daily, 2 weekly, 2 monthly**. Пароли и дампы — чувствительные данные; не выкладывать в открытый доступ.
---
@@ -264,7 +268,7 @@ VM 200 **не входит** в задание vzdump (образ ~380 ГБ, н
### Подготовка на хосте
- Те же креды, что для бэкапа: **`/root/.restic-yandex.env`** (RESTIC_REPOSITORY, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY), **`/root/.restic-password`**.
- Те же креды, что для бэкапа: `**/root/.restic-yandex.env`** (RESTIC_REPOSITORY, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY), `**/root/.restic-password**`.
- Установлены **restic** и **FUSE** (для `restic mount`): `apt install restic fuse`.
- Восстановление делаем **на раздел с достаточным местом** (например `/mnt/backup/restore-...`), не в `/tmp`.
@@ -272,10 +276,12 @@ VM 200 **не входит** в задание vzdump (образ ~380 ГБ, н
В репозитории два вида снимков (различаются по полю **Paths** в `restic snapshots`):
| Paths в снимке | Откуда | Что внутри |
|------------------|--------|-----------|
| `/mnt/backup` | backup-restic-yandex.sh | Всё кроме photos: proxmox/dump, proxmox/etc-pve, databases/, other/, vps/ |
| `/mnt/backup/photos` | backup-restic-yandex-photos.sh | Только каталог photos (библиотека Immich) |
| Paths в снимке | Откуда | Что внутри |
| -------------------- | ------------------------------ | ------------------------------------------------------------------------- |
| `/mnt/backup` | backup-restic-yandex.sh | Всё кроме photos: proxmox/dump, proxmox/etc-pve, databases/, other/, vps/ |
| `/mnt/backup/photos` | backup-restic-yandex-photos.sh | Только каталог photos (библиотека Immich) |
При восстановлении **конфигов, паролей, дампов БД, vzdump** — брать снимок с path **/mnt/backup**. При восстановлении **фото** — брать снимок с path **/mnt/backup/photos**.
@@ -289,14 +295,16 @@ restic snapshots
### Сводка: что откуда восстанавливать
| Что восстановить | Путь в снимке (основной репо) | Снимок | Способ |
|----------------------|--------------------------------------|-------------|--------|
| Один LXC/VM (vzdump) | /mnt/backup/proxmox/dump/dump/... | /mnt/backup | Скрипт mount + cp (см. ниже) |
| Конфиги /etc/pve | /mnt/backup/proxmox/etc-pve/ | /mnt/backup | restic restore --path ... |
| Vaultwarden (пароли) | /mnt/backup/other/vaultwarden/ | /mnt/backup | restic restore --path ... |
| Дампы БД | /mnt/backup/databases/... | /mnt/backup | restic restore --path ... |
| VPS, other | /mnt/backup/vps/, other/ | /mnt/backup | restic restore --path ... |
| Фото Immich | /mnt/backup/photos/ | **/mnt/backup/photos** | restic restore из снимка photos |
| Что восстановить | Путь в снимке (основной репо) | Снимок | Способ |
| -------------------- | --------------------------------- | ---------------------- | ------------------------------- |
| Один LXC/VM (vzdump) | /mnt/backup/proxmox/dump/dump/... | /mnt/backup | Скрипт mount + cp (см. ниже) |
| Конфиги /etc/pve | /mnt/backup/proxmox/etc-pve/ | /mnt/backup | restic restore --path ... |
| Vaultwarden (пароли) | /mnt/backup/other/vaultwarden/ | /mnt/backup | restic restore --path ... |
| Дампы БД | /mnt/backup/databases/... | /mnt/backup | restic restore --path ... |
| VPS, other | /mnt/backup/vps/, other/ | /mnt/backup | restic restore --path ... |
| Фото Immich | /mnt/backup/photos/ | **/mnt/backup/photos** | restic restore из снимка photos |
---
@@ -305,23 +313,21 @@ restic snapshots
Чтобы не выкачивать весь репо, используется **mount** и копирование одного файла.
1. Узнать имя нужного архива в снимке (например CT 107):
```bash
```bash
restic ls latest --path /mnt/backup/proxmox/dump/dump | grep vzdump-lxc-107
```
```
Использовать снимок с path `/mnt/backup` (не photos).
2. Запустить скрипт (он сам монтирует, копирует файл, размонтирует):
```bash
```bash
/root/scripts/restore-one-vzdump-from-restic.sh latest /mnt/backup/proxmox/dump/dump/vzdump-lxc-107-YYYY_MM_DD-HH_MM_SS.tar.zst /mnt/backup
```
```
Файл появится в `/mnt/backup/vzdump-lxc-107-....tar.zst`.
3. Восстановить контейнер из файла (как в разделе 1 выше):
```bash
```bash
pct create 999 /mnt/backup/vzdump-lxc-107-....tar.zst --restore 1 --storage local-lvm
pct set 999 --net0 name=eth0,bridge=vmbr0,gw=192.168.1.1,ip=192.168.1.199/24,type=veth
pct start 999
```
```
Если скрипта нет — вручную: `restic mount /mnt/backup/restic-mount &`, подождать, скопировать из `.../restic-mount/ids/<SNAPSHOT_ID>/mnt/backup/proxmox/dump/dump/vzdump-lxc-107-....tar.zst` в нужное место, затем `fusermount -u /mnt/backup/restic-mount`.
@@ -331,15 +337,15 @@ restic snapshots
1. Выбрать снимок с path **/mnt/backup** (по дате): `restic snapshots`.
2. Восстановить только каталог etc-pve:
```bash
```bash
restic restore SNAPSHOT_ID --target /mnt/backup/restore-etc-pve --path /mnt/backup/proxmox/etc-pve
```
```
Файлы появятся в `/mnt/backup/restore-etc-pve/mnt/backup/proxmox/etc-pve/` (архивы `etc-pve-*.tar.gz`, `etc-host-configs-*.tar.gz`).
3. Распаковать нужный архив в корень (как в разделе 2 выше):
```bash
```bash
tar -xzf /mnt/backup/restore-etc-pve/mnt/backup/proxmox/etc-pve/etc-pve-YYYYMMDD-HHMM.tar.gz -C /
tar -xzf /mnt/backup/restore-etc-pve/mnt/backup/proxmox/etc-pve/etc-host-configs-YYYYMMDD-HHMM.tar.gz -C /
```
```
4. При необходимости поправить сеть и перезапустить сервисы.
---
@@ -348,9 +354,9 @@ restic snapshots
1. Снимок с path **/mnt/backup**.
2. Восстановить каталог vaultwarden:
```bash
```bash
restic restore SNAPSHOT_ID --target /mnt/backup/restore-vw --path /mnt/backup/other/vaultwarden
```
```
Результат: `/mnt/backup/restore-vw/mnt/backup/other/vaultwarden/vaultwarden-data-*.tar.gz`.
3. Скопировать архив на хост, откуда можно отправить на CT 103, либо распаковать во временный каталог и скопировать каталог `data/` на CT 103 в `/opt/docker/vaultwarden/` (остановив Vaultwarden). Детали — раздел 6 выше.
@@ -392,34 +398,126 @@ restic restore SNAPSHOT_ID --target /mnt/backup/restore-db --path /mnt/backup/da
### Восстановление прочего (VPS, векторы RAG) из restic
- **VPS Миран / MTProto:**
`restic restore SNAPSHOT_ID --target /mnt/backup/restore-vps --path /mnt/backup/vps`
Дальше — копировать нужные файлы на VPS по разделам 78.
`restic restore SNAPSHOT_ID --target /mnt/backup/restore-vps --path /mnt/backup/vps`
Дальше — копировать нужные файлы на VPS по разделам 78.
- **Векторы RAG (ct105-vectors):**
`restic restore SNAPSHOT_ID --target /mnt/backup/restore-other --path /mnt/backup/other/ct105-vectors`
Дальше — по разделу 9.
`restic restore SNAPSHOT_ID --target /mnt/backup/restore-other --path /mnt/backup/other/ct105-vectors`
Дальше — по разделу 9.
---
## Скрипты на хосте Proxmox
| Скрипт | Назначение | Cron |
|--------|------------|------|
| `/root/scripts/backup-vps-miran.sh` | Бэкап VPS Миран: БД бота, voice_users, S3 (Miran) | 0 1 * * * |
| `/root/scripts/backup-vps-mtproto.sh` | Копирование конфигов MTProto + сайт с VPS Германия (185.103.253.99) | 45 1 * * * |
| `/root/scripts/backup-ct101-pgdump.sh` | Логический дамп БД Nextcloud из CT 101 | 15 1 * * * |
| `/root/scripts/backup-immich-photos.sh` | Копирование библиотеки фото Immich (rsync с VM 200) | 30 1 * * * |
| `/root/scripts/backup-vps-mtproto.sh` | Копирование конфигов MTProto + сайт с VPS Германия (185.103.253.99) | 45 1 * * * |
| `/root/scripts/backup-etc-pve.sh` | Бэкап /etc/pve и конфигов хоста | 15 2 * * * |
| `/root/scripts/backup-ct104-pgdump.sh` | Логический дамп БД Paperless из CT 104 | 30 2 * * * |
| `/root/scripts/backup-vaultwarden-data.sh` | Копирование данных Vaultwarden (пароли) из CT 103 | 45 2 * * * |
| `/root/scripts/backup-ct103-gitea-pgdump.sh` | Логический дамп БД Gitea из CT 103 | 0 3 * * * |
| `/root/scripts/notify-vzdump-success.sh` | Проверка локального vzdump за последние 2 ч, отправка сводки в Telegram | 0 3 * * * |
| `/root/scripts/backup-vm200-pgdump.sh` | Логический дамп БД Immich с VM 200 | 15 3 * * * |
| `/root/scripts/backup-ct105-vectors.sh` | Копирование векторов RAG (vectors.npz) из CT 105 | 30 3 * * * |
| `/root/scripts/backup-restic-yandex.sh` | Выгрузка /mnt/backup (без photos) в Yandex S3 (restic), retention 3/2/2 | 0 4 * * * |
| `/root/scripts/backup-restic-yandex-photos.sh` | Выгрузка только /mnt/backup/photos в Yandex S3 (тот же репо), retention 3/2/2 | 0 1 * * * |
| `/root/scripts/backup-restic-yandex-photos.sh` | Выгрузка только /mnt/backup/photos в Yandex S3 (тот же репо), retention 3/2/2 | 10 4 * * * |
| `/root/scripts/notify-telegram.sh` | Шлюз отправки уведомлений в Telegram (вызывают скрипты бэкапов) | — |
Задание vzdump (LXC/VM) настраивается в Proxmox UI (расписание 02:00). **05:00** оставлено свободным для плановой перезагрузки сервера.
### Диагностика пустых дампов БД и архива Vaultwarden
Если дампы БД (Nextcloud, Paperless, Gitea), архив Vaultwarden или векторы RAG (CT 105) получаются по 20 байт — в копию попал только пустой gzip/tar, команда внутри контейнера не отдала данные. Скрипты при размере < 512 байт завершаются с ошибкой и выводят stderr. Для векторов проверьте путь `/home/rag-service/data/vectors` в CT 105: `pct exec 105 -- ls -la /home/rag-service/data/vectors`.
**Частая причина дампов БД:** PostgreSQL в контейнере требует пароль (md5/scram). Скрипты берут пароль из **Vaultwarden** (Bitwarden CLI `bw`): объекты **NEXTCLOUD** (поле `dbpassword` или пароль), **PAPERLESS**, **GITEA**. На хосте нужны: `bw`, при необходимости `jq`, разблокировка по мастер-паролю из файла `/root/.bw-master` (см. [Переключение скриптов на секреты из Vaultwarden](proxmox-phase1-backup.md#переключение-скриптов-на-секреты-из-vaultwarden) в proxmox-phase1-backup.md).
**Проверка вручную (без подавления stderr):** зайти в контейнер и выполнить дамп, чтобы увидеть сообщение об ошибке:
```bash
# CT 101 (Nextcloud)
pct exec 101 -- docker exec nextcloud-db-1 pg_dump -U nextcloud nextcloud | head -5
# CT 104 (Paperless)
pct exec 104 -- docker exec paperless-db-1 pg_dump -U paperless paperless | head -5
# CT 103 (Gitea)
pct exec 103 -- docker exec gitea-db-1 pg_dump -U gitea gitea | head -5
# CT 103 (Vaultwarden) — каталог data
pct exec 103 -- ls -la /opt/docker/vaultwarden/data
pct exec 103 -- tar cf - -C /opt/docker/vaultwarden data | wc -c
```
**Запуск из cron и доступ к Vaultwarden (bw):** В cron окружение ограничено: часто `PATH` не содержит `/usr/local/bin`, где обычно установлен `bw`. Скрипты дампов БД (ct101, ct104, ct103) в начале задают `export PATH="/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${PATH}"`, поэтому при запуске из cron `bw` и `jq` находятся без правки crontab. Нужно: 1) файл с мастер-паролем, например `/root/.bw-master` (chmod 600), и при необходимости переменная `BW_MASTER_PASSWORD_FILE=/root/.bw-master`; 2) один раз с интерактивной сессии: `bw config server https://vault.katykhin.ru`, `bw login` (сохранит сессию в конфиг); 3) при каждом запуске скрипт делает `bw unlock --passwordfile "$BW_MASTER_PASSWORD_FILE" --raw` и подставляет пароль БД. Если вручную дамп идёт, а из cron — нет, проверьте: наличие `/root/.bw-master`, права доступа, что `bw` доступен по этому PATH (запустите скрипт через `env -i PATH=/usr/local/bin:/usr/bin:/bin /root/scripts/backup-ct103-gitea-pgdump.sh` для имитации cron).
### Почему размер дампа меньше размера БД на диске
`pg_database_size()` показывает **размер БД на диске**: данные таблиц + **индексы** + TOAST (сжатые длинные значения) + свободное место и bloat. **pg_dump** выводит только логические данные в виде SQL: самих данных индексов в дампе нет (только команды `CREATE INDEX`), поэтому несжатый дамп часто **меньше** размера БД. После gzip сжатие даёт ещё примерно 2,54×. Итог: БД 2GB на диске → несжатый дамп 200600MB → сжатый 50200 MB нормален (особенно для Nextcloud с большими индексами по `oc_filecache`).
Если сомневаетесь, проверьте несжатый размер и число таблиц:
```bash
# Несжатый размер дампа (на хосте)
gunzip -c /mnt/backup/databases/ct101-nextcloud/nextcloud-db-YYYYMMDD-HHMM.sql.gz | wc -c
# Таблиц в дампе
gunzip -c /mnt/backup/databases/ct101-nextcloud/nextcloud-db-YYYYMMDD-HHMM.sql.gz | grep -c '^CREATE TABLE '
# Таблиц в живой БД (в контейнере)
pct exec 101 -- docker exec nextcloud-db-1 psql -U nextcloud -d nextcloud -t -c "SELECT count(*) FROM information_schema.tables WHERE table_schema = 'public';"
```
Числа таблиц должны совпадать. Несжатый размер для Nextcloud 2GB на диске обычно 200600 MB. При необходимости запустите бэкап с проверкой: `VERIFY_BACKUP=1 /root/scripts/backup-ct101-pgdump.sh` — скрипт выведет несжатый размер и число таблиц в дампе.
---
## Уведомления в Telegram
После **успешного** выполнения каждого бэкапа в Telegram отправляется короткое сообщение (заголовок с эмодзи + краткая сводка). Уведомления приходят по завершении соответствующего скрипта; для локального vzdump — по cron в **03:00** (проверка файлов за последние 2 часа).
| Заголовок | Когда | Тело сообщения |
|-----------|------|----------------|
| 🖥️ VPS Миран | после 01:00 | Резервное копирование завершено. БД, voice_users, S3 (telegram-helper-bot). Размер копии: X. |
| 🗄️ Nextcloud (БД) | после 01:15 | Резервное копирование завершено. Дамп БД Nextcloud. Размер: X. |
| 📷 Фото Immich (rsync) | после 01:30 | Резервное копирование завершено. Библиотека фото синхронизирована. Размер: X. |
| 🌐 VPS MTProto (DE) | после 01:45 | Резервное копирование завершено. Конфиги MTProto и сайт (VPS DE). Размер архива: X. |
| 💾 Backup local | 03:00 | Резервное копирование завершено. Локальный vzdump (LXC/VM). Контейнеров/ВМ: N, объём: X ГБ. Время завершения: HH:MM. |
| ⚙️ Конфиги хоста | после 02:15 | Резервное копирование завершено. Архивы /etc/pve и конфигов сети. Размер: X. |
| 🗄️ Paperless (БД) | после 02:30 | Резервное копирование завершено. Дамп БД Paperless. Размер: X. |
| 🔐 Vaultwarden | после 02:45 | Резервное копирование завершено. Данные Vaultwarden. Размер архива: X. |
| 🗄️ Gitea (БД) | после 03:00 | Резервное копирование завершено. Дамп БД Gitea. Размер: X. |
| 🗄️ Immich (БД) | после 03:15 | Резервное копирование завершено. Дамп БД Immich. Размер: X. |
| 📐 Векторы RAG | после 03:30 | Резервное копирование завершено. Архив векторов RAG. Размер: X. |
| ☁️ Restic Yandex | после 04:00 | Резервное копирование завершено. Снимок в Yandex: N файлов, размер X. |
| 📷 Restic Yandex (photos) | после 04:10 | Резервное копирование завершено. Снимок фото в Yandex: N файлов, размер X. |
**Размер в сообщениях** — фактический размер файла (apparent size), а не занятое место на диске. Если видите **4.0K** или **8.0K** у дампа БД или архива Vaultwarden — копия может быть пустой или почти пустой (ошибка доступа к контейнеру, пустая БД, неверный путь). Скрипты при размере ниже порога (10KB для дампов БД и Vaultwarden, 1KB для MTProto) добавляют в сообщение строку: *«⚠️ Подозрительно малый размер — проверьте…»*. В этом случае проверьте на хосте: имя контейнера БД, путь к данным, логи скрипта.
**Единая точка отправки (шлюз):** скрипт **`/root/scripts/notify-telegram.sh`**. Все источники уведомлений вызывают только его и не обращаются к Telegram API напрямую. Токен и chat_id хранятся в одном конфиге на хосте Proxmox.
**Конфиг на хосте:** `/root/.telegram-notify.env` с переменными `TELEGRAM_BOT_TOKEN` и `TELEGRAM_CHAT_ID`. В репозитории лежит пример: **`scripts/telegram-notify.env.example`** — скопируйте его на хост в `/root/.telegram-notify.env` и подставьте свои значения:
```bash
cp /path/to/scripts/telegram-notify.env.example /root/.telegram-notify.env
chmod 600 /root/.telegram-notify.env
```
**Как получить креды:**
1. **Токен бота:** в Telegram написать [@BotFather](https://t.me/BotFather), команда `/newbot`, следовать подсказкам — получите токен вида `123456789:ABCdef...`.
2. **Chat ID:** отправить боту любое сообщение, затем в браузере открыть
`https://api.telegram.org/bot<TOKEN>/getUpdates`
В ответе в `updates[].message.chat.id` — ваш chat_id (число; для групп — отрицательное).
Если конфига или кредов нет, шлюз тихо выходит с 0 и не ломает вызывающие скрипты.
**Позже** тот же шлюз можно вызывать с VM 200 или с VPS (например по SSH на хост Proxmox) — отдельно не реализовано, архитектура это допускает.
---
## Связанные документы
@@ -427,3 +525,4 @@ restic restore SNAPSHOT_ID --target /mnt/backup/restore-db --path /mnt/backup/da
- [Стратегия бэкапов (фаза 1)](proxmox-phase1-backup.md) — общий план и принятые решения.
- [Архитектура](../architecture/architecture.md) — хост, IP, доступ.
- [VM 200 (Immich)](../containers/container-200.md) — сервисы, пути, .env.