Второй PBS дома: off-site бэкапы без S3, без белого IP, без VPS-посредника
Продолжение истории про переезд с пяти VPS на один дедик. В прошлый раз я остановился на схеме «PBS в LXC на хосте + offsite-синхронизация в S3». Эту схему я в итоге пересобрал — оказалось, что S3 здесь лишнее звено.
Где я остановился в прошлый раз
В предыдущей статье я описал свою схему бэкапов на четыре уровня:
- ZFS-снэпшоты на пуле (мгновенные, против «ой снёс БД»).
- PBS в LXC на том же хосте (полноценные incremental).
- Sync job из PBS в S3 (offsite).
- Discourse-бэкапы прямо в S3 (страховка приложения).
Уровень 3 меня всё это время смутно не устраивал. Назову три причины — и одну из них вы вряд ли встречали в туториалах.
S3 ломает дедупликацию PBS. Сама прелесть PBS — в чанковой дедупликации: новый бэкап весит дельту от предыдущего, а не полный размер VM. При синхронизации в S3 PBS складывает чанки как объекты, и да, формально дедуп сохраняется. Но проверить целостность бэкапа = скачать значительный объём чанков обратно. И тут вступает причина два.
Селектел вроде свой — но если он завтра решит поднять цены или потерять регион, у меня нет рычага. Это деньги, которые капают каждый месяц, и которые в момент катастрофы могут не отдать данные (legal hold, заморозка аккаунта, что угодно). Для бэкапов это критично — именно тогда, когда ты теряешь основной сайт, тебе обязательно нужно встать на резерв без переговоров с провайдером.
Невозможен прямой restore. В S3 лежат байтики. Чтобы из них восстановиться, нужно сначала развернуть промежуточный PBS, синкнуть данные обратно, и только потом делать qmrestore. Если у меня горит дедик — мне нужно второе место, готовое восстанавливать прямо сейчас. Не «через час, когда я подниму временный PBS».
Логичный вывод: вместо S3 нужен второй полноценный PBS, расположенный физически в другом месте, готовый принимать sync jobs и при необходимости отдавать бэкапы напрямую.
Где этот второй PBS жить
Варианты были такие:
- Арендовать у хостера — это deja vu из прошлой статьи, я как раз ушёл от модели «много счетов».
- Дешёвый VPS со своим PBS — пара десятков евро в месяц, неконтролируемая площадка, и ещё одна точка отказа.
- Поставить дома на свой NAS — место есть, NAS живёт у меня в гостиной, RAID, ИБП, провайдер не блокирует SSD ¯\(ツ)/¯.
Третий вариант выигрывает по всем параметрам, кроме одного: NAS дома за NAT, провайдер белый IP мне не даст без танцев и оплаты. Прокинуть порт нельзя, морочиться с DDNS и динамическим IP не хочется, держать порт PBS открытым в интернет — отдельно нет.
Тут на сцену выходит mesh, который у меня уже есть — Netbird, описанный в прошлой статье. К нему уже подключены дедик, peer-сервер, мой ноут и пара старых машин. Добавить туда NAS — это одна установка агента и один setup key. NAS получит адрес 100.x.x.x в той же приватной mesh-сети, и для дедика он станет таким же досягаемым, как сосед по vmbr1.
Что получилось в итоге
flowchart LR
subgraph DC["🇵🇱 Dedik OVH Warsaw"]
PVE["Proxmox Host<br/>"]
subgraph LXC102["LXC 102"]
PBS1["PBS primary<br/>10.10.10.3"]
end
VMs["VM 200, 201, 202, 203<br/>LXC 120, 121, 122"]
PVE --- LXC102
PVE --- VMs
end
subgraph HOME["🏠 Дом за NAT"]
NAS["Synology NAS"]
subgraph COMPOSE["Container Manager"]
NB["netbird agent"]
PBS2["PBS secondary<br/>:8007"]
NB -.network_mode.- PBS2
end
NAS --- COMPOSE
end
subgraph CLOUD["☁️ Netbird Cloud"]
MGMT["Management<br/>+ Signal"]
end
VMs -."vzdump backup".-> PBS1
PVE <-->|control plane| MGMT
NB <-->|control plane| MGMT
PBS1 <==>|"PBS Sync Job<br/>WireGuard tunnel"| PBS2
classDef dc fill:#2d3748,stroke:#4a5568,color:#e2e8f0
classDef home fill:#22543d,stroke:#38a169,color:#f0fff4
classDef cloud fill:#2c5282,stroke:#3182ce,color:#ebf8ff
class DC dc
class HOME,COMPOSE home
class CLOUD cloudVM и LXC бэкапятся локально на PBS primary в LXC 102 — это быстро, по localhost, с полным дедупом. Раз в сутки sync job в PBS primary льёт дельту на PBS secondary на NAS-е через mesh. Snapshots остаются в обоих местах, дедупликация работает на обоих PBS независимо, а restore можно делать с любого из двух — оба «настоящие».
Через mesh идёт только sync — это значит, что NAS снаружи не виден ничем, никаких портов, никаких DDNS. Через облако Netbird бегает только control plane (управление пирами), сами бэкапы текут напрямую WireGuard-туннелем дедик ↔ NAS.
Установка: что менялось от стандартного PBS
Большая часть установки — это обычный docker-compose проект в Synology Container Manager: pbs из community-сборки ayufan/proxmox-backup-server плюс sidecar netbird-агент в общем network namespace. Подробности по compose-файлу, лимитам памяти, монтированию /etc, /lib, /backups — у меня уже расписаны в отдельной заметке про сам процесс. Здесь сфокусируюсь на том, что специфично для второго PBS, не на азах.
Hostname в mesh — осмысленный
1environment:
2 - NB_HOSTNAME=synology-pbs-offsite
Когда пиров становится больше десятка, имена вроде synology начинают терять смысл. synology-pbs-offsite сразу говорит, что это (a) NAS, (b) с PBS, (c) для off-site роли. На дедике в storage.cfg будет фигурировать ровно это имя.
ACL Netbird — пускаем только дедик
В Netbird-консоли я создал группу pbs-sync и положил туда только два пира: PVE-хост и Synology. Правило: всё остальное в группе default к pbs-sync ходить не может. Ноут, peer-сервер, старые машины — никто из них не видит порт 8007 на NAS. Если завтра меня попросят дать кому-то RDP на ноут — он не получит автоматически доступ к моим бэкапам.
Это, кстати, главное преимущество mesh с ACL над голым WireGuard: в WG все, кто в туннеле, видят всех — ACL делаются iptables-ами руками и быстро превращаются в кашу.
Datastore на отдельном томе
В Synology я создал отдельный shared folder /volume2/PBS на разделе с большими механическими дисками (BTRFS, RAID 5). NVMe-том на NAS-е оставил для горячих данных и Docker. PBS не нужен IOPS на бэкапах — ему нужен объём, и шумные HDD-шпиндели тут идеально подходят.
1volumes:
2 - ./etc:/etc/proxmox-backup
3 - ./logs:/var/log/proxmox-backup
4 - ./lib:/var/lib/proxmox-backup
5 - ./backups:/backups
Сам datastore в UI PBS указываю как /backups. Размер — 4 TB, на текущем объёме данных хватит на пару лет с ретеншном keep-daily=7 keep-weekly=4 keep-monthly=12 keep-yearly=3.
Sync Job — самое интересное
Это новая для меня часть, в прошлой статье её не было. У PBS есть встроенная фича Remote + Sync Job: один PBS может быть «клиентом» другого, тянуть с него снапшоты и складывать в свой datastore.
Шаг 1: Remote на стороне primary
На основном PBS (LXC 102) добавляю secondary как remote target. В UI: Configuration → Remotes → Add.
- Remote ID:
nas-offsite - Host:
synology-pbs-offsite(это имя из Netbird DNS, оно резолвится с любого пира) - Auth ID:
sync@pbs(отдельный юзер на secondary, см. ниже) - Password / Token: пароль
sync@pbs - Fingerprint: SHA-256 отпечаток сертификата secondary
Fingerprint снимается на secondary одной командой:
1docker exec pbs proxmox-backup-manager cert info | grep -i fingerprint
Шаг 2: Пользователь для sync на secondary
На NAS-е, внутри контейнера pbs:
1proxmox-backup-manager user create sync@pbs --password 'LongRandomPassword2026'
2proxmox-backup-manager acl update /datastore/main DatastoreBackup --auth-id sync@pbs
3proxmox-backup-manager acl update /remote DatastorePowerUser --auth-id sync@pbs
[!IMPORTANT] Пароль должен быть длинным и без спецсимволов. PBS при создании юзера через
proxmox-backup-managerпринимает любой пароль молча, а на API-уровне отвергает слабые с401 Unauthorized. Поймал это на ровном месте, потерял час, пока не догадался создать нового юзера с нормальным паролем. По уму PBS должен на этапе создания ругаться, но не ругается.
Шаг 3: Sync Job
На primary PBS: Datastore → main → Sync Jobs → Add.
- Local Datastore:
main(это datastore на primary) - Remote:
nas-offsite - Remote Datastore:
main(это datastore на secondary) - Schedule:
daily 03:30(после ежедневного бэкапа в 02:00, до утра) - Owner:
sync@pbs - Remove vanished:
yes(если на primary удалил старый снапшот ретеншном — пусть и на secondary удалится; иначе secondary распухнет)
Жмёшь Run Now → видишь в логах, как PBS чанк за чанком льёт данные. Первый раз — полный объём (у меня вышло около 180 GB на старте), все последующие — только дельта.
Скорость
Меня волновало: NAS дома, канал у меня 600/600 Mbps, дедик в Варшаве, между ними где-то 30 ms. Через WireGuard в mesh PBS пушит со скоростью около 400 Mbit/s — это упирается в шифрование на NAS-е, не в канал. Для off-site бэкапа это с большим запасом. Дневная дельта в пределах 5-15 GB уходит за пару минут.
Восстановление: оно действительно работает с обеих сторон
Сценарий «дедик горит / OVH лежит / диск посыпался» прорабатывал так:
- Беру любой свободный сервер (или поднимаю Proxmox в виртуалке локально, или беру у нового хостера новый дедик).
- Ставлю на него Netbird-агент, добавляю в mesh.
- Подключаю NAS как PBS Storage:
Datacenter → Storage → Add → Proxmox Backup Server, serversynology-pbs-offsite, usersync@pbs. qmrestoreнужной VM из NAS-овского datastore. Никакого посредничества, никакого «сначала развернуть PBS» — secondary уже PBS.
Тестовый restore Discourse-VM на пустой Proxmox-инстанс отработал за 18 минут (4 GB RAM, 50 GB диск). С S3 это была бы вся ночь.
Стоимость
| Что | Раньше | Сейчас |
|---|---|---|
| Объект-хранилище в S3 для бэкапов | ~$8/мес за 200 GB | $0 |
| Egress при тестовом restore | ~$15 за 100 GB | $0 |
| Время на off-site restore | от часа | минуты |
| Контроль над хранилищем | у Selectel | у меня |
NAS стоит дома и так — он не был куплен ради этой задачи, просто стал её бонусом. Электричество — копейки, потому что spin-down неактивных дисков работает.
Что я понял по дороге
Mesh — это инфраструктурный примитив, а не «VPN для удалёнки». В прошлой статье я писал про Netbird в контексте админдоступа и обхода блокировок. Сейчас я понимаю, что mesh — это нулевой уровень всей моей инфры. Любой новый узел сначала подключается в mesh, потом обретает роль. Это меняет архитектурное мышление: ты перестаёшь делить серверы на «свои/чужие/публичные», все они становятся пирами с разными ACL.
S3 для бэкапов был интеллектуальной ленью. Я выбрал S3 потому, что это «канонический паттерн», а не потому, что он подходил моей задаче. Второй PBS подходит лучше по всем параметрам, кроме одного — его надо самому поставить и настроить. И то — один вечер.
Off-site != offline. Многие пишут, что бэкап должен быть offline (air-gapped). У меня secondary всегда онлайн через mesh, и формально он не защищён от ransomware, который добежал бы до primary и потом через sync job портил бы snapshots на secondary. Защита тут — флаг verify-new и ZFS/BTRFS-снэпшоты на самом Synology на уровне shared folder. PBS на secondary не может удалить или испортить снэпшот выше себя — это делает только хост NAS-а. Получается, что secondary online для удобства, но под ним — offline-history, которую sync-логика не достанет.
Что дальше
Из доделок по бэкап-цепочке:
- Verify jobs на secondary раз в две недели, чтобы знать, что данные на NAS реально читаемые, а не «лежат». Раньше эту роль играла гипотетическая возможность скачать из S3 и проверить — теперь это родная фича PBS.
- Третий уровень offsite для уж совсем параноидального сценария «дом и дедик одновременно». Скорее всего, это будет периодический ручной экспорт критичных datastore-снапшотов на внешний USB-диск, который лежит у родителей в другом городе. Не автоматизация, а ритуал — раз в квартал поехал, обновил.
Если у вас уже есть NAS дома и mesh между серверами — у вас есть готовый off-site PBS, вам осталось его собрать. Если нет — посмотрите на это под другим углом: домашний NAS перестаёт быть «штукой для фоток с отпуска», он становится частью продакшен-инфраструктуры. И это, на удивление, нормально.
В следующей заметке расскажу про verify jobs, prune-стратегию для двух PBS и про то, как считать реальный RPO/RTO для такой схемы. Если интересно — пишите в комментариях.