Bash-скрипт для ежедневного резервного копирования данных между S3-compatible хранилищами через rclone.
Проект реализует автоматический cloud-to-cloud backup: данные копируются из исходного remote-хранилища в backup-хранилище, складываются в папку с датой запуска, логируются и очищаются по retention-политике.
- Bash
- rclone
- systemd
- systemd timer
- Linux
- S3-compatible storage
- Ежедневное резервное копирование между cloud storage remote;
- создание отдельной папки под каждый день в формате
DD.MM.YYYY; - безопасное копирование через
rclone copy; - защита от параллельного запуска через
flock; - логирование в отдельный log-файл;
- retention-политика с удалением старых backup-папок;
- настройка через environment variables;
- запуск как
systemd oneshotservice; - запуск по расписанию через
systemd timer.
cloud-backup-sync/
├── README.md
├── r2_to_s3_daily.sh
├── .gitignore
└── systemd/
├── cloud-backup-sync.service.example
└── cloud-backup-sync.timer.example
Скрипт выполняет две основные операции.
Данные копируются из исходного remote в backup remote:
rclone copy "$SRC" "$DST"Каждый запуск создаёт отдельную папку с текущей датой:
s3:backup-bucket/24.04.2026/
Используется именно rclone copy, а не rclone sync, потому что backup пишется в новую dated-папку. Это снижает риск случайного удаления данных в уже созданных резервных копиях.
После копирования скрипт получает список папок в backup bucket, выбирает папки в формате:
DD.MM.YYYY
Затем удаляет те, которые старше заданного количества дней.
По умолчанию:
KEEP_DAYS=3Это означает, что хранятся:
- сегодняшний backup;
- backup за вчера;
- backup за позавчера.
Более старые папки удаляются через:
rclone purgeСкрипт настраивается через переменные окружения.
Пример:
SRC_REMOTE="r2:source-bucket/"
DST_REMOTE="s3:backup-bucket"
KEEP_DAYS=3
RCLONE_CFG="/etc/rclone/rclone.conf"
LOG_DIR="/var/log/rclone"
LOG_FILE="/var/log/rclone/cloud-backup-sync.log"
LOCK_FILE="/var/lock/cloud-backup-sync.lock"
TZ="Europe/Moscow"Файл:
r2_to_s3_daily.sh
Ключевые части реализации:
set -euo pipefailИспользуется строгий режим Bash, чтобы скрипт завершался при ошибках, обращении к несуществующим переменным и ошибках в pipeline.
exec 9>"$LOCK_FILE"
if ! flock -n 9; then
echo "Another backup is running, exiting." >>"$LOG_FILE"
exit 0
fiЭта часть защищает backup от параллельного запуска.
DATE_TAG="$(date +%d.%m.%Y)"
DST="${DST_BUCKET}/${DATE_TAG}/"Эта часть формирует папку текущего дня.
Пример service-файла находится здесь:
systemd/cloud-backup-sync.service.example
Пример:
[Unit]
Description=Daily cloud-to-cloud backup with retention
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
Environment=SRC_REMOTE=r2:source-bucket/
Environment=DST_REMOTE=s3:backup-bucket
Environment=KEEP_DAYS=3
Environment=RCLONE_CFG=/etc/rclone/rclone.conf
ExecStart=/usr/local/bin/r2_to_s3_daily.shType=oneshot используется потому, что backup-скрипт запускается, выполняет задачу и завершается.
Пример timer-файла находится здесь:
systemd/cloud-backup-sync.timer.example
Пример:
[Unit]
Description=Run cloud backup sync daily
[Timer]
OnCalendar=*-*-* 00:00:00
Persistent=true
Unit=cloud-backup-sync.service
[Install]
WantedBy=timers.targetPersistent=true нужен для того, чтобы systemd запустил пропущенную задачу после включения сервера, если сервер был выключен в момент расписания.
Скопировать скрипт:
sudo cp r2_to_s3_daily.sh /usr/local/bin/r2_to_s3_daily.sh
sudo chmod +x /usr/local/bin/r2_to_s3_daily.shСкопировать systemd service и timer:
sudo cp systemd/cloud-backup-sync.service.example /etc/systemd/system/cloud-backup-sync.service
sudo cp systemd/cloud-backup-sync.timer.example /etc/systemd/system/cloud-backup-sync.timerПеречитать systemd:
sudo systemctl daemon-reloadВключить timer:
sudo systemctl enable cloud-backup-sync.timer
sudo systemctl start cloud-backup-sync.timerПроверить timer:
systemctl list-timers --all | grep cloud-backup-syncЗапустить backup вручную:
sudo systemctl start cloud-backup-sync.serviceПроверить статус:
sudo systemctl status cloud-backup-sync.service --no-pagerПо умолчанию лог пишется в файл:
/var/log/rclone/cloud-backup-sync.log
Посмотреть последние строки:
tail -n 100 /var/log/rclone/cloud-backup-sync.logТакже можно смотреть логи systemd:
journalctl -u cloud-backup-sync.service -n 100 --no-pagerПроверить, что rclone установлен:
rclone versionПроверить список remote:
rclone listremotes --config /etc/rclone/rclone.confПроверить доступ к исходному remote:
rclone lsf r2:source-bucket/ --config /etc/rclone/rclone.confПроверить доступ к backup remote:
rclone lsf s3:backup-bucket/ --config /etc/rclone/rclone.confПроверить активные locks:
ls -la /var/lock/cloud-backup-sync.lockВ репозитории нельзя хранить:
- реальные access keys;
- secret keys;
- production
rclone.conf; - реальные имена приватных bucket;
- логи с приватными путями;
- backup-данные;
.envфайлы.
Файл rclone.conf должен храниться только на сервере, например:
/etc/rclone/rclone.conf
В публичный GitHub добавляются только обезличенные примеры.
- Bash-скрипт для cloud-to-cloud backup;
- копирование через
rclone copy; - dated folders в формате
DD.MM.YYYY; - retention-политика на заданное количество дней;
- удаление старых backup-папок через
rclone purge; - защита от параллельного запуска через
flock; - логирование в отдельный файл;
- конфигурация через environment variables;
- systemd oneshot service;
- systemd timer для ежедневного запуска;
- команды диагностики и ручного запуска.
Цель проекта — показать практический DevOps-подход к резервному копированию данных: автоматизация backup-процесса, защита от параллельных запусков, логирование, retention-политика и интеграция с systemd.
Проект демонстрирует навыки работы с Linux, Bash, rclone, systemd, S3-compatible storage и эксплуатацией серверной инфраструктуры.