Перейти к содержанию

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 · Первый ручной прогон

sudo /opt/vaultwarden/backups/offsite.sh
sudo tail -20 /var/log/vaultwarden-offsite.log

Ожидание в логе:

[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

# На VPS, от root:
sudo crontab -e

Добавить (не удаляя существующие строки):

# Off-site бэкап Vaultwarden на ragserver (VAULT-01)
35 3 * * * /opt/vaultwarden/backups/offsite.sh >/dev/null 2>&1

Проверить:

sudo crontab -l | grep offsite
# ожидание: строка с offsite.sh


Шаг 7 · Мониторинг

Через 2 дня (10.08.2026 после 04:00):

sudo tail -50 /var/log/vaultwarden-offsite.log
# ожидание: 2 записи "OK" с ростом числа архивов

Разово, если хочешь метрику в 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