Содержание

Резервное копирование

Docker

Для рез. копирования данных на томах создаётся контейнер, который подхватывает все тома целевого контейнера, монтирует каталог с рез. копиями и запускает команду архивации.

#!/bin/bash
 
t=$(date +%F) # дата вида 2017-01-01
weekDay=$(date +%u) # номер дня недели
sourceDir="/home/user/home"
backupDir="/home/user/backup"
localDir="$backupDir/local"
nasDir="$backupDir/nas"
remoteDir="$backupDir/remote"
 
wpDbPass=$(cat $sourceDir/wp-db/wp-db-root.txt)
ncDbPass=$(cat $sourceDir/nc-db/nc-db-root.txt)
protoprismDbPass=$(cat $sourceDir/photoprism-db/photoprism-db-root.txt)
webtreesDbPass=$(cat $sourceDir/webtrees-db/webtrees-db-root.txt)
backupPass=$(cat $backupDir/backup-pass.txt)
 
 
# Выгрузить базы MySQL
# https://severalnines.com/database-blog/how-encrypt-your-mysql-mariadb-backups
docker exec wp-db mysqldump -uroot -p$wpDbPass -A |gzip |openssl enc -aes-256-cbc -pbkdf2 -k $backupPass > $localDir/$t-wp.sql.gz
docker exec nc-db  mysqldump -uroot -p$ncDbPass -A |gzip |openssl enc -aes-256-cbc -pbkdf2 -k $backupPass > $localDir/$t-nc.sql.gz
docker exec photoprism-db  mysqldump -uroot -p$protoprismDbPass -A |gzip |openssl enc -aes-256-cbc -pbkdf2 -k $backupPass > $localDir/$t-photoprism.sql.gz
docker exec webtrees-db  mysqldump -uroot -p$webtreesDbPass -A |gzip |openssl enc -aes-256-cbc -pbkdf2 -k $backupPass > $localDir/$t-webtrees.sql.gz
# Файлы проекта
# https://www.tecmint.com/encrypt-decrypt-files-tar-openssl-linux/
tar --create --preserve-permissions --gzip $sourceDir | \
openssl enc -e -aes-256-cbc -pbkdf2 -out $localDir/$t-project.tar.gz -pass pass:$backupPass
 
# Файлы контейнеров
if [ $weekDay -eq 2 ]
then
# Удалить старые файлы старше 2 недель
find $localDir -name '*.gz*' -mtime +14 -exec rm -f {} \;
# Full backup
docker run --rm --volumes-from wp -v $backupDir:/backup ubuntu \
tar --create --preserve-permissions --gzip --listed-incremental=/backup/wp-0.snar --level=0 /var/www/html | \
openssl enc -e -aes-256-cbc -pbkdf2 -out $localDir/$t-wp-full.tar.gz -pass pass:$backupPass
 
docker run --rm --volumes-from wiki -v $backupDir:/backup ubuntu \
tar --create --preserve-permissions --gzip --listed-incremental=/backup/wiki-0.snar --level=0 /var/www/html | \
openssl enc -e -aes-256-cbc -pbkdf2 -out $localDir/$t-wiki-full.tar.gz -pass pass:$backupPass
 
docker run --rm --volumes-from nc -v $backupDir:/backup ubuntu \
tar --create --preserve-permissions --gzip --listed-incremental=/backup/nc-0.snar --level=0 /var/www/html | \
openssl enc -e -aes-256-cbc -pbkdf2 -out $localDir/$t-nc-full.tar.gz -pass pass:$backupPass
 
docker run --rm --volumes-from photoprism -v $backupDir:/backup ubuntu \
tar --create --preserve-permissions --gzip --listed-incremental=/backup/photoprism-0.snar --level=0 /photoprism | \
openssl enc -e -aes-256-cbc -pbkdf2 -out $localDir/$t-photoprism-full.tar.gz -pass pass:$backupPass
 
docker run --rm --volumes-from webtrees -v $backupDir:/backup ubuntu \
tar --create --preserve-permissions --gzip --listed-incremental=/backup/webtrees-0.snar --level=0 /var/www/html | \
openssl enc -e -aes-256-cbc -pbkdf2 -out $localDir/$t-webtrees-full.tar.gz -pass pass:$backupPass
 
docker run --rm --volumes-from bepasty -v $backupDir:/backup ubuntu \
tar --create --preserve-permissions --gzip --listed-incremental=/backup/bepasty-0.snar --level=0 /srv/bepasty | \
openssl enc -e -aes-256-cbc -pbkdf2 -out $localDir/$t-bepasty-full.tar.gz -pass pass:$backupPass
 
docker run --rm --volumes-from phpsysinfo -v $backupDir:/backup ubuntu \
tar --create --preserve-permissions --gzip --listed-incremental=/backup/phpsysinfo-0.snar --level=0 /var/www/html | \
openssl enc -e -aes-256-cbc -pbkdf2 -out $localDir/$t-phpsysinfo-full.tar.gz -pass pass:$backupPass
 
else
# Copy snars for diff backup
for f in $backupDir/*-0.snar; do cp "$f" "${f/-0.snar/-1.snar}"; done
# Differential backup
docker run --rm --volumes-from wp -v $backupDir:/backup ubuntu \
tar --create --preserve-permissions --gzip --listed-incremental=/backup/wp-1.snar /var/www/html | \
openssl enc -e -aes-256-cbc -pbkdf2 -out $localDir/$t-wp.tar.gz -pass pass:$backupPass
 
docker run --rm --volumes-from wiki -v $backupDir:/backup ubuntu \
tar --create --preserve-permissions --gzip --listed-incremental=/backup/wiki-1.snar /var/www/html | \
openssl enc -e -aes-256-cbc -pbkdf2 -out $localDir/$t-wiki.tar.gz -pass pass:$backupPass
 
docker run --rm --volumes-from nc -v $backupDir:/backup ubuntu \
tar --create --preserve-permissions --gzip --listed-incremental=/backup/nc-1.snar /var/www/html | \
openssl enc -e -aes-256-cbc -pbkdf2 -out $localDir/$t-nc.tar.gz -pass pass:$backupPass
 
docker run --rm --volumes-from photoprism -v $backupDir:/backup ubuntu \
tar --create --preserve-permissions --gzip --listed-incremental=/backup/photoprism-1.snar /photoprism | \
openssl enc -e -aes-256-cbc -pbkdf2 -out $localDir/$t-photoprism.tar.gz -pass pass:$backupPass
 
docker run --rm --volumes-from webtrees -v $backupDir:/backup ubuntu \
tar --create --preserve-permissions --gzip --listed-incremental=/backup/webtrees-1.snar /var/www/html | \
openssl enc -e -aes-256-cbc -pbkdf2 -out $localDir/$t-webtrees.tar.gz -pass pass:$backupPass
 
docker run --rm --volumes-from bepasty -v $backupDir:/backup ubuntu \
tar --create --preserve-permissions --gzip --listed-incremental=/backup/bepasty-1.snar /srv/bepasty | \
openssl enc -e -aes-256-cbc -pbkdf2 -out $localDir/$t-bepasty.tar.gz -pass pass:$backupPass
 
docker run --rm --volumes-from phpsysinfo -v $backupDir:/backup ubuntu \
tar --create --preserve-permissions --gzip --listed-incremental=/backup/phpsysinfo-1.snar /var/www/html | \
openssl enc -e -aes-256-cbc -pbkdf2 -out $localDir/$t-phpsysinfo.tar.gz -pass pass:$backupPass
 
fi
 
 
# Разбивка на файлы по 2 ГБ, созданных за последние сутки
# https://www.tecmint.com/split-large-tar-into-multiple-files-of-certain-size/
bigFiles=($(find $localDir -type f -size +2G -mtime -1))
for f in ${bigFiles[*]}; do
split -b 2G "$f" "$localDir/$(basename "$f").part"
done
 
 
# Выгрузка на NAS
mount $nasDir
# https://linuxize.com/post/bash-check-if-file-exists/
if [ -f "$nasDir/server-available" ]
then
rsync --delete --recursive --size-only --include="*.gz" --exclude="*" $localDir/ $nasDir
fi
umount $nasDir
 
 
# Выгрузка на удалённый сервер (WebDAV)
mount $remoteDir
if [ -f "$remoteDir/server-available" ]
then
rsync --delete --recursive --size-only --max-size=2G --exclude="lost+found" --exclude="server-available" $localDir/ $remoteDir
fi
# sleep 10m
umount $remoteDir

https://severalnines.com/database-blog/how-encrypt-your-mysql-mariadb-backups
https://www.tecmint.com/encrypt-decrypt-files-tar-openssl-linux
https://docs.docker.com/storage/volumes/#backup-restore-or-migrate-data-volumes

Монолит

  1. Делать резервные копии двух баз MySQL
  2. Делать резервные копии корневой папки веб-сервера вместе с содержимым симлинков внутри неё
  3. Сжимать бэкап для экономии места
  4. Шифровать его, чтобы бэкап можно было класть на публичные сервисы
  5. Синхронизировать результат с удалёнными хранилищами, в данном случае по webdav на 4shared.
  6. Делать полную копию файлов каждое воскресенье, прочие дни - дифференциальную копию
  7. Удалять старые резервные копии старше двух недель

Создать каталоги

# Для резервных копий (на sdcard)
mkdir /media/sdcard/backup
# Для зашифрованных резервных копий
mkdir /media/sdcard/backup/encrypted
# Для монтирования 4shared WebDAV
mkdir /media/webdav/4shared

Установить и настроить программу для монтирования webdav

# Установить компонент webdav
sudo apt-get install davfs2 -y
# На вопрос монтирования каталогов от непривилегированных пользователей ответить "да".
# Чтобы изменить это позже:
dpkg-reconfigure davfs2
 
# Включить пользователя в группу davfs2 (если он не root)
sudo usermod -aG davfs2 $USER
 
# Прописать файл адреса, логина и пароля для подключения, права на файл
mkdir $HOME/.davfs2
touch $HOME/.davfs2/secrets
chmod 600 $HOME/.davfs2/secrets
nano $HOME/.davfs2/secrets
# для рута - файл /etc/davfs2/secrets
 
# Вставить в конец файла строки примерно следующего вида
# (в данном случае путь указывает сразу в папку на удалённом сервере):
https://nextcloud.domain.ru/remote.php/webdav/backup login password
https://webdav.4shared.com/backup/orangepipc2 login password
https://webdav.yandex.ru/backup login password
 
# Для непривилегированного пользователя необходимо прописать строку в /etc/fstab,
# иначе монтироваться вручную не будет. В данном случае, noauto - не монтировать при запуске системы
echo "# davfs" >> /etc/fstab
echo "https://webdav.4shared.com/backup/orangepipc2  /home/user/backup/remote   davfs   user,rw,noauto   0   0" >> /etc/fstab
 
# Убрать предупреждение при монтировании
/sbin/mount.davfs: warning: the server does not support locks
# Раскомментировать и исправить параметр
sudo sed -i '/use_locks/c use_locks 0' /etc/davfs2/davfs2.conf
 
# После этого, можно будет монтировать удалённый каталог командой
mount $HOME/backup/remote
# и размонтировать
umount $HOME/backup/remote

Использование утилиты davfs2 для монтирования сетевых облачных хранилищ по протоколу WebDAV

Скрипт

#!/bin/bash
 
BACKUP_TIME=$(date +"%F") # дата вида 2017-01-01
DOW=$(date +%u) # Day of week
SOURCE_DIR="/var/www/html"
BACKUP_DIR="/media/usb8gb/backup"
ENCRYPTED_DIR="$BACKUP_DIR/encrypted"
WEBDAV_SITE_4SHARED="https://webdav.4shared.com/backup/orangepipc2" # 4shared
WEBDAV_DIR_4SHARED="/media/4shared"
FULL="$BACKUP_TIME-files-full.tar.gz"
DIFF="$BACKUP_TIME-files-diff.tar.gz"
FULL_ENCRYPTED="$FULL.aes" # Зашифрованный архив с файлами веб-сервера
DIFF_ENCRYPTED="$DIFF.aes"
PASS="pass" # Пароль для шифрования
 
# Параметры MySQL
DB_USER="mysqluser"
DB_PASS="mysqlpass"
WP_DB="wordpress"
CLOUD_DB="cloud"
WP_DB_FILE="$BACKUP_TIME-$WP_DB.sql"
CLOUD_DB_FILE="$BACKUP_TIME-$CLOUD_DB.sql"
WP_DB_FILE_COMPRESSED="$WP_DB_FILE.gz"
CLOUD_DB_FILE_COMPRESSED="$CLOUD_DB_FILE.gz"
WP_DB_FILE_ENCRYPTED="$WP_DB_FILE_COMPRESSED.aes"
CLOUD_DB_FILE_ENCRYPTED="$CLOUD_DB_FILE_COMPRESSED.aes"
 
# Выгрузить базы MySQL
mysqldump --add-drop-table -u$DB_USER -p$DB_PASS $WP_DB > $BACKUP_DIR/$WP_DB_FILE
mysqldump --add-drop-table -u$DB_USER -p$DB_PASS $CLOUD_DB > $BACKUP_DIR/$CLOUD_DB_FILE
gzip $BACKUP_DIR/*.sql # Сжать базы MySQL
openssl enc -aes-256-cbc -pbkdf2 -in $BACKUP_DIR/$WP_DB_FILE_COMPRESSED -out $ENCRYPTED_DIR/$WP_DB_FILE_ENCRYPTED -pass pass:$PASS
openssl enc -aes-256-cbc -pbkdf2 -in $BACKUP_DIR/$CLOUD_DB_FILE_COMPRESSED -out $ENCRYPTED_DIR/$CLOUD_DB_FILE_ENCRYPTED -pass pass:$PASS
 
if [ $DOW -eq 7 ]
then
# Удалить старые файлы старше 2 недель
find $ENCRYPTED_DIR -name '*.aes' -mtime +14 -exec rm -f {} \;
# Резервное копирование (полный)
tar --create --preserve-permissions --dereference --gzip --listed-incremental="$BACKUP_DIR/level-0.snar" --level=0 --file=$BACKUP_DIR/$FULL $SOURCE_DIR
openssl enc -aes-256-cbc -pbkdf2 -in $BACKUP_DIR/$FULL -out $ENCRYPTED_DIR/$FULL_ENCRYPTED -pass pass:$PASS
else
# Резервное копирование (дифференциальное)
cp "$BACKUP_DIR/level-0.snar" "$BACKUP_DIR/level-1.snar"
tar --create --preserve-permissions --dereference --gzip --listed-incremental="$BACKUP_DIR/level-1.snar" --file=$BACKUP_DIR/$DIFF $SOURCE_DIR
openssl enc -aes-256-cbc -pbkdf2 -in $BACKUP_DIR/$DIFF -out $ENCRYPTED_DIR/$DIFF_ENCRYPTED -pass pass:$PASS
fi
 
# Удалить исходные незашифрованные архивы
find $BACKUP_DIR -name '*.gz' -exec rm -f {} \;
# Закачать полученные зашифрованные архивы на удалённые серверы
# Смонтировать удалённые каталоги webdav
mount -t davfs $WEBDAV_SITE_4SHARED $WEBDAV_DIR_4SHARED
# Синхронизировать локальные каталоги с удалёнными (только зашифрованные файлы)
rsync --delete --recursive --size-only --exclude="lost+found" $ENCRYPTED_DIR/ $WEBDAV_DIR_4SHARED
# Иногда бывало, что после окончания работы rsync
# данные реально не успевают закачаться на серверы, по этой причине
# после отмонтирования разделов WebDAV эти данные попадают в /var/cache,
# что забивает системный раздел. По этой причине, в скрипт вставлена пауза.
# sleep 30m
# Размонтировать удалённые каталоги WebDAV
umount -t davfs $WEBDAV_DIR_4SHARED

Создать файл backup.sh, вставить туда код и отредактировать пути, логины и пароли.

Сделать файлы скриптов запускаемыми:

chmod +x backup.sh

Настроить планировщик:

crontab -e
# Cleanup davfs cache
0 8 * * 7 root rm -rf /var/cache/davfs2/*
# Backup
0 3 * * * /root/backup.sh

Проблемы

В один прекрасный день WebDAV перестал синхронизировать, на попытку смонтировать каталог выдаёт:

/sbin/mount.davfs: found PID file /var/run/mount.davfs/media-webdav.pid.
Either /media/webdav is used by another process,
or another mount process ended irregular
 
# Решение:
rm /var/run/mount.davfs/media-webdav.pid

Полезные команды

Вывести список БД

mysql -u root -p111111
show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| cloud              |
| mysql              |
| performance_schema |
| sys                |
| wordpress          |
+--------------------+
cp -L -r /var/www/html ~/backup

(‘-L’ ,‘–dereference’ - Follow symbolic links when copying from them. With this option, cp cannot create a symbolic link. For example, a symlink (to regular file) in the source tree will be copied to a regular file in the destination tree.)

Скопировать папку рекурсивно с сохранением всех свойств файлов

# папка backup создастся на usb8gb
cp -rp /media/sdcard/backup /media/usb8gb

Посмотреть размеры вложенных каталогов и вывести общий размер

du -sch /media/sdcard/*

Borg

Latest release: https://github.com/borgbackup/borg/releases/latest
Installation: https://borgbackup.readthedocs.io/en/stable/installation.html

Quick start: https://borgbackup.readthedocs.io/en/stable/quickstart.html

borg init --encryption=none /path/to/repo # create unencrypted repo (not recommended)
borg create /path/to/repo::Monday ~/src ~/Documents # "Monday" is a name

https://habr.com/ru/company/flant/blog/420055/

Restic

https://restic.net/ Перспективная программка.

Документация: https://restic.readthedocs.io/en/latest/010_introduction.html

DeAndre Queary - Restic Complete Guide

Urbackup

https://www.urbackup.org/index.html Сервер + клиенты для большинства ОС.

https://christitus.com/urbackup/

Инфо

Программы для бэкапа на линуксе - Borg, Veeam agent

Rclone - rsync for cloud storage

Статьи

Общие

A Shell Script for a Complete WordPress Backup
Резервное копирование WordPress с помощью mysqldump и tar
Syncing folders to any remote Cloud Storage from a headless Linux server
Backing Up Your WordPress Files

MySQL

Создание резервной копии БД

date

Linux and Unix date command

tar

tar syntax
Using tar to Perform Incremental Dumps
BackupYourSystem
BackupYourSystem/TAR
Создание инкрементального архива с помощью утилиты tar

crontab

Linux and Unix crontab command

Чистка старых файлов

Delete Files Older Than x Days on Linux
Delete files older than X days +
`find -name` pattern that matches multiple patterns
Unix find: multiple file types
Linux find command

rsync

10 Practical Examples of Rsync Command in Linux
Re: rsync - including only certain extensions
Linux and Unix rsync command
Rsync: мощная утилита для быстрого, гибкого удаленного и локального копирования файлов