Проект

Общее

Профиль

Локальные бэкапы Vaultwarden » История » Версия 1

Redmine Admin, 25.03.2026 10:32

1 1 Redmine Admin
<div class="backup-guide">
2
  <h2>💾 Вариант 1: Локальные бэкапы с ротацией (базовый)</h2>
3
  <p>Автоматизированное резервное копирование данных Vaultwarden с хранением архивов и очисткой устаревших файлов.</p>
4
5
  <div class="info-box">
6
    <strong>📋 Что делает скрипт:</strong>
7
    <ul>
8
      <li>Останавливает контейнер для консистентности БД</li>
9
      <li>Создаёт сжатый архив с данными</li>
10
      <li>Запускает контейнер обратно</li>
11
      <li>Удаляет бэкапы старше заданного периода</li>
12
      <li>Ведёт логирование всех операций</li>
13
    </ul>
14
  </div>
15
16
  <h3>1️⃣ Создайте скрипт бэкапа</h3>
17
  <pre class="bash"><code>sudo nano /usr/local/bin/vaultwarden-backup.sh</code></pre>
18
19
  <p>Вставьте содержимое:</p>
20
  <pre class="bash"><code>#!/bin/bash
21
# Vaultwarden Backup Script
22
# Резервное копирование данных Vaultwarden
23
24
set -e  # Выход при ошибке
25
26
# === НАСТРОЙКИ ===
27
SOURCE_DIR="/root/vaultwarden/data"           # Источник данных
28
BACKUP_DIR="/root/vaultwarden/backups"        # Куда сохранять бэкапы
29
RETENTION_DAYS=30                             # Сколько дней хранить бэкапы
30
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
31
BACKUP_FILE="vaultwarden_backup_${TIMESTAMP}.tar.gz"
32
LOG_FILE="/var/log/vaultwarden-backup.log"
33
34
# Создаем папку для бэкапов если нет
35
mkdir -p "$BACKUP_DIR"
36
37
# Логирование
38
log() {
39
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
40
}
41
42
log "=== Начало бэкапа ==="
43
44
# Останавливаем контейнер для консистентности БД (опционально, но рекомендуется)
45
log "Остановка контейнера vaultwarden..."
46
docker stop vaultwarden 2&gt;/dev/null || true
47
48
# Создаем архив
49
log "Создание архива: $BACKUP_FILE"
50
tar -czf "${BACKUP_DIR}/${BACKUP_FILE}" -C "$(dirname "$SOURCE_DIR")" "$(basename "$SOURCE_DIR")"
51
52
# Запускаем контейнер обратно
53
log "Запуск контейнера vaultwarden..."
54
docker start vaultwarden 2&gt;/dev/null || true
55
56
# Удаляем старые бэкапы
57
log "Удаление бэкапов старше $RETENTION_DAYS дней..."
58
find "$BACKUP_DIR" -name "vaultwarden_backup_*.tar.gz" -type f -mtime +$RETENTION_DAYS -delete -print | tee -a "$LOG_FILE"
59
60
# Показываем размер и список бэкапов
61
log "Размер нового бэкапа: $(du -h "${BACKUP_DIR}/${BACKUP_FILE}" | cut -f1)"
62
log "Бэкапы в хранилище:"
63
ls -lh "$BACKUP_DIR"/*.tar.gz 2&gt;/dev/null | tee -a "$LOG_FILE"
64
65
log "=== Бэкап завершен успешно ==="</code></pre>
66
67
  <h3>2️⃣ Сделайте скрипт исполняемым</h3>
68
  <pre class="bash"><code>sudo chmod +x /usr/local/bin/vaultwarden-backup.sh</code></pre>
69
70
  <h3>3️⃣ Протестируйте вручную</h3>
71
  <pre class="bash"><code>sudo /usr/local/bin/vaultwarden-backup.sh</code></pre>
72
73
  <p>Проверьте, что файл появился:</p>
74
  <pre class="bash"><code>ls -lh /root/vaultwarden/backups/</code></pre>
75
76
  <div class="success-box">
77
    <strong>✅ Ожидаемый результат:</strong>
78
    <pre><code>total 1.2M
79
-rw-r--r-- 1 root root 1.2M Jun 22 03:00 vaultwarden_backup_20260622_030001.tar.gz</code></pre>
80
  </div>
81
82
  <h3>4️⃣ Настройте автоматизацию через Cron</h3>
83
  <p>Откройте crontab root-пользователя:</p>
84
  <pre class="bash"><code>sudo crontab -e</code></pre>
85
86
  <p>Добавьте строку для ежедневного бэкапа в 3:00 ночи:</p>
87
  <pre class="cron"><code>0 3 * * * /usr/local/bin/vaultwarden-backup.sh</code></pre>
88
89
  <div class="tip-box">
90
    <strong>💡 Примеры других расписаний:</strong>
91
    <ul>
92
      <li><code>0 2 * * 0</code> — каждое воскресенье в 2:00</li>
93
      <li><code>0 */6 * * *</code> — каждые 6 часов</li>
94
      <li><code>30 4 1 * *</code> — 1-го числа каждого месяца в 4:30</li>
95
    </ul>
96
  </div>
97
98
  <h3>❓ Почему с остановкой контейнера?</h3>
99
  <div class="warning-box">
100
    <strong>⚠️ Важно:</strong> Vaultwarden использует SQLite. Хотя он устойчив к бэкапам "на лету", 
101
    остановка контейнера гарантирует <strong>100% консистентность базы данных</strong> и исключает 
102
    риск повреждения архива при одновременной записи.
103
  </div>
104
105
  <h3>🔧 Полезные команды для управления бэкапами</h3>
106
  <pre class="bash"><code># Просмотр логов бэкапа
107
tail -f /var/log/vaultwarden-backup.log
108
109
# Ручной запуск бэкапа с выводом в реальном времени
110
sudo /usr/local/bin/vaultwarden-backup.sh
111
112
# Проверка статуса cron-задачи
113
sudo systemctl status cron
114
115
# Тестовый прогон cron (сухой запуск)
116
sudo run-parts --test /etc/cron.daily
117
118
# Восстановление из бэкапа (пример)
119
tar -xzf /root/vaultwarden/backups/vaultwarden_backup_20260622_030001.tar.gz -C /root/vaultwarden/</code></pre>
120
121
  <h3>🗂️ Структура после настройки</h3>
122
  <pre><code>/root/vaultwarden/
123
├── data/                    # Рабочие данные Vaultwarden
124
├── backups/                 # Папка для архивов
125
│   ├── vaultwarden_backup_20260620_030001.tar.gz
126
│   ├── vaultwarden_backup_20260621_030001.tar.gz
127
│   └── vaultwarden_backup_20260622_030001.tar.gz  ← последний
128
├── docker-compose.yml
129
└── ...
130
131
/var/log/
132
└── vaultwarden-backup.log   # Лог-файл скрипта</code></pre>
133
134
  <h3>🔄 Альтернатива: бэкап без остановки контейнера</h3>
135
  <p>Если простой сервиса недопустим, можно использовать <code>docker exec</code> для копирования "на лету":</p>
136
  <pre class="bash"><code># Заменить секцию остановки/запуска контейнера на:
137
log "Копирование данных без остановки..."
138
docker exec vaultwarden tar -czf - /data &gt; "${BACKUP_DIR}/${BACKUP_FILE}"</code></pre>
139
  <p class="small">⚠️ Используйте этот метод только если понимаете риски: при активной записи в БД архив может быть неполным.</p>
140
</div>
141
142
<style>
143
.backup-guide {
144
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
145
  line-height: 1.6;
146
  color: #2c3e50;
147
  max-width: 100%;
148
  font-size: 14px;
149
}
150
.backup-guide h2 {
151
  color: #1a5276;
152
  border-bottom: 3px solid #3498db;
153
  padding-bottom: 0.6em;
154
  margin: 1.5em 0 1em;
155
  font-size: 1.4em;
156
}
157
.backup-guide h3 {
158
  color: #2874a6;
159
  margin: 1.3em 0 0.7em;
160
  background: #ebf5fb;
161
  padding: 0.6em 0.9em;
162
  border-left: 4px solid #3498db;
163
  border-radius: 0 4px 4px 0;
164
  font-size: 1.15em;
165
}
166
.backup-guide p { margin: 0.6em 0; }
167
.backup-guide pre {
168
  background: #1e1e1e;
169
  color: #d4d4d4;
170
  padding: 1em;
171
  border-radius: 5px;
172
  overflow-x: auto;
173
  font-size: 0.85em;
174
  margin: 0.7em 0;
175
  border: 1px solid #3a3a3a;
176
}
177
.backup-guide code {
178
  font-family: "Consolas", "Monaco", "Courier New", monospace;
179
  color: #ce9178;
180
}
181
.backup-guide pre code { color: #d4d4d4; }
182
.backup-guide pre.bash::before {
183
  content: "🐧 Bash";
184
  display: block;
185
  background: #4a5568;
186
  color: #fff;
187
  padding: 0.25em 0.6em;
188
  margin: -1em -1em 0.8em -1em;
189
  font-size: 0.75em;
190
  border-radius: 4px 4px 0 0;
191
  font-weight: 600;
192
}
193
.backup-guide pre.cron::before {
194
  content: "⏰ Crontab";
195
  display: block;
196
  background: #7b68a3;
197
  color: #fff;
198
  padding: 0.25em 0.6em;
199
  margin: -1em -1em 0.8em -1em;
200
  font-size: 0.75em;
201
  border-radius: 4px 4px 0 0;
202
  font-weight: 600;
203
}
204
.backup-guide ul {
205
  padding-left: 1.6em;
206
  margin: 0.5em 0;
207
}
208
.backup-guide li { margin: 0.35em 0; }
209
.backup-guide .info-box {
210
  background: #e8f4fd;
211
  border: 1px solid #b6d4fe;
212
  border-left: 4px solid #3498db;
213
  padding: 1em 1.2em;
214
  margin: 1em 0;
215
  border-radius: 0 5px 5px 0;
216
}
217
.backup-guide .success-box {
218
  background: #e6f7ee;
219
  border: 1px solid #b7e4c7;
220
  border-left: 4px solid #27ae60;
221
  padding: 1em 1.2em;
222
  margin: 1em 0;
223
  border-radius: 0 5px 5px 0;
224
}
225
.backup-guide .warning-box {
226
  background: #fff3cd;
227
  border: 1px solid #ffeaa7;
228
  border-left: 4px solid #f39c12;
229
  padding: 1em 1.2em;
230
  margin: 1em 0;
231
  border-radius: 0 5px 5px 0;
232
}
233
.backup-guide .tip-box {
234
  background: #f0f7ff;
235
  border: 1px solid #cfe2ff;
236
  border-left: 4px solid #17a2b8;
237
  padding: 1em 1.2em;
238
  margin: 1em 0;
239
  border-radius: 0 5px 5px 0;
240
}
241
.backup-guide .small {
242
  font-size: 0.9em;
243
  color: #666;
244
  font-style: italic;
245
}
246
.backup-guide a {
247
  color: #2980b9;
248
  text-decoration: none;
249
}
250
.backup-guide a:hover { text-decoration: underline; }
251
@media (max-width: 768px) {
252
  .backup-guide { font-size: 13px; }
253
  .backup-guide pre { font-size: 0.8em; }
254
}
255
</style>