Off-site бэкап Vaultwarden — runbook (VAULT-01)¶
Цель: GPG-архивы Vaultwarden с VPS ежедневно копируются на ragserver. Если VPS сгорит — есть свежий бэкап на домашнем сервере.
Логика:
- Локальный backup.sh на VPS работает как раньше (03:15 MSK).
- Новый offsite.sh через 20 минут (03:35) синхронизирует *.gpg на ragserver через AmneziaWG (10.8.1.12).
- Retention на ragserver — 90 дней (втрое больше локального 30).
Схема:
VPS 46.17.99.183 ragserver 192.168.1.200
┌─────────────────────────────┐ ┌────────────────────────────┐
│ /opt/vaultwarden/backups/ │ │ /home/oswold/backups/ │
│ ├── backup.sh (03:15) │ │ └── vaultwarden/ │
│ ├── *.tar.gz.gpg │ rsync │ └── *.tar.gz.gpg │
│ │ (retention 30d) │ ──────▶ │ (retention 90d) │
│ └── offsite.sh (03:35) ──────┐ │ │
└─────────────────────────────┘ │ └────────────────────────────┘
│
└── SSH через AmneziaWG (10.8.1.12)
Шаг 1 · На ragserver: создать директорию для бэкапов¶
# На ragserver (192.168.1.200), от юзера oswold:
mkdir -p /home/oswold/backups/vaultwarden
chmod 700 /home/oswold/backups /home/oswold/backups/vaultwarden
ls -ld /home/oswold/backups/vaultwarden
# ожидание: drwx------ oswold oswold
Шаг 2 · На VPS: создать SSH-ключ для root → oswold@ragserver¶
Отдельный ключ только для offsite-бэкапа, ограниченный на remote-стороне.
# На VPS (46.17.99.183), от root:
sudo -i
ssh-keygen -t ed25519 -N '' -f /root/.ssh/id_ed25519_offsite -C "vw-offsite-vps@ragserver"
cat /root/.ssh/id_ed25519_offsite.pub
# Скопируй вывод — понадобится в шаге 3
Шаг 3 · На ragserver: авторизовать ключ с ограничениями¶
command= ограничивает что можно делать под этим ключом. Только rsync и минимальные test/find для retention:
# На ragserver, от oswold:
mkdir -p ~/.ssh
chmod 700 ~/.ssh
touch ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
# Добавь строку (замени <ПАБЛИК-КЛЮЧ> на вывод из шага 2):
cat >> ~/.ssh/authorized_keys <<'EOF'
# Vaultwarden off-site backup from VPS (ограниченный, только rsync+find)
restrict,command="/home/oswold/backups/rrsync-vw.sh" ssh-ed25519 <ПАБЛИК-КЛЮЧ> vw-offsite-vps@ragserver
EOF
Wrapper rrsync-vw.sh — фильтрует какие команды пускаем через ssh:
cat > /home/oswold/backups/rrsync-vw.sh <<'WRAP'
#!/usr/bin/env bash
# Разрешаем только: rsync-серверный режим, test -d/-w, find для retention
case "$SSH_ORIGINAL_COMMAND" in
"rsync --server "*"/home/oswold/backups/vaultwarden/") ;;
"test -d '/home/oswold/backups/vaultwarden' && test -w '/home/oswold/backups/vaultwarden'") ;;
"find '/home/oswold/backups/vaultwarden' -name '*.gpg' -mtime +"*" -delete -print") ;;
"find '/home/oswold/backups/vaultwarden' -name '*.gpg' | wc -l") ;;
"du -sh '/home/oswold/backups/vaultwarden' | cut -f1") ;;
*)
echo "Rejected: $SSH_ORIGINAL_COMMAND" >&2
exit 1
;;
esac
eval "$SSH_ORIGINAL_COMMAND"
WRAP
chmod 700 /home/oswold/backups/rrsync-vw.sh
Шаг 4 · На VPS: проверить connect и скопировать offsite.sh¶
# На VPS, от root:
# 4.1 — проверка ключа (первый раз спросит fingerprint)
sudo ssh -i /root/.ssh/id_ed25519_offsite oswold@10.8.1.12 \
"test -d '/home/oswold/backups/vaultwarden' && echo OK"
# ожидание: OK
# 4.2 — скачать скрипт (или скопировать вручную из skeletons/)
sudo curl -fsSL \
"https://raw.githubusercontent.com/oswold1979/alatyr-infra-kb/main/skeletons/backup-offsite-vaultwarden.sh" \
-o /opt/vaultwarden/backups/offsite.sh
# ⚠️ репо приватный — если curl не работает, скопируй руками:
# scp skeletons/backup-offsite-vaultwarden.sh root@46.17.99.183:/opt/vaultwarden/backups/offsite.sh
sudo chmod 700 /opt/vaultwarden/backups/offsite.sh
sudo chown root:root /opt/vaultwarden/backups/offsite.sh
Внутри offsite.sh укажи ключ. По умолчанию ssh берёт ~/.ssh/id_ed25519. Мы используем отдельный id_ed25519_offsite, поэтому либо:
Вариант A — прописать в ~/.ssh/config (для root):
sudo tee -a /root/.ssh/config <<'EOF'
Host 10.8.1.12
User oswold
IdentityFile /root/.ssh/id_ed25519_offsite
IdentitiesOnly yes
StrictHostKeyChecking accept-new
EOF
sudo chmod 600 /root/.ssh/config
Вариант B — правкой скрипта -i /root/.ssh/id_ed25519_offsite в -e "ssh ...". Вариант A аккуратнее.
Шаг 5 · Первый ручной прогон¶
Ожидание в логе:
[2026-08-08 03:35:12] Старт rsync /opt/vaultwarden/backups/*.gpg → oswold@10.8.1.12:/home/oswold/backups/vaultwarden/
sending incremental file list
vaultwarden-backup-2026-08-08_031500.tar.gz.gpg
...
[2026-08-08 03:35:15] OK: на ragserver сейчас 13 архивов, суммарно 312K
Проверка на ragserver:
# С ragserver, от oswold:
ls -lh /home/oswold/backups/vaultwarden/ | head
# ожидание: 13 файлов .tar.gz.gpg, самый свежий сегодня
Шаг 6 · Cron¶
Добавить (не удаляя существующие строки):
# Off-site бэкап Vaultwarden на ragserver (VAULT-01)
35 3 * * * /opt/vaultwarden/backups/offsite.sh >/dev/null 2>&1
Проверить:
Шаг 7 · Мониторинг¶
Через 2 дня (10.08.2026 после 04:00):
Разово, если хочешь метрику в Uptime Kuma (задача 28):
- HTTP push (Passive) monitor с URL, куда offsite.sh пингует после успеха
- Или проверка mtime /var/log/vaultwarden-offsite.log через systemd timer
Диагностика¶
| Симптом | Причина | Что делать |
|---|---|---|
FATAL: 10.8.1.12 не пингуется |
AmneziaWG упал | systemctl status amneziawg-quick@awg0 на VPS |
Permission denied (publickey) |
Ключ не авторизован | Перепроверить authorized_keys на ragserver |
Rejected: rsync ... |
Wrapper блокирует | Посмотри что в $SSH_ORIGINAL_COMMAND, добавь в whitelist |
rsync: connection unexpectedly closed |
ragserver в дауне | ping 192.168.1.200 из локалки |
Что дальше — VAULT-02 (test restore)¶
См. restore-test-vaultwarden.md — раз в квартал:
1. Скачать любой .gpg с ragserver
2. Расшифровать GPG-паролем из бумажного сейфа
3. Развернуть в изолированную папку
4. Убедиться что vaultwarden контейнер запускается на нём
Автор: агент, 08.08.2026