Выкладывать бекапы проектов (сайтов) на Яндекс.Диск может понадобиться по нескольким причинам, например, из-за нехватки места на сервере (хостинге, VDS, VPS) или для повышения безопасности хранения бекапов (на случай, если сервер без рейда и он выйдет из строя).
В связи с этим я написал для себя и решил выложить для других небольшой bash-скрипт для бекапа на Яндекс.Диск. Функции скрипта:
— Создание на сервере бекапа проектов (файлов + баз данных MySQL);
— Авторизация на Яндекс.Диске в качестве приложения (по токену, более безопасный способ, чем использование логина и пароля);
— Отправка бекапов с сервера на Яндекс.Диск;
— Удаление старых бекапов с Яндекс.Диска для экономии места (настраивается максимальное количество хранимых бекапов);
— Запись и отправка лога на e-mail (настраивается).
Для того, чтобы воспользоваться скриптом, необходимо сначала получить токен от Яндекс.Диска. Приступим.
1. Логинимся на Яндексе под аккаунтом, на диск которого будем делать бекап, заходим на oauth.yandex.ru и нажимаем «Зарегистрировать новое приложение».

2. Заполняем название приложения (например, «backup») и выдаём нужные права в разделе «Яндекс.Диск REST API», а именно: «Доступ к информации о Диске» и «Доступ к папке приложения на Диске».

Ниже на той же странице под полем «Callback URL» нажимаем «подставить URL для разработки» и нажимаем «Сохранить»:

3. После сохранения параметров приложения нас перенаправят на страницу с данными о приложении:

4. Теперь получим сам токен (если хотите, можете почитать подробнее об этом в мануале Яндекса), для этого копируем ID, подставляем в конец URL https://oauth.yandex.ru/authorize?response_type=token&client_id=, переходим по получившемуся адресу и подтверждаем выдачу разрешений приложению:

В итоге на странице будет отображён токен, который выдается не менее, чем на 1 год, поэтому если скрипт бекапа вдруг перестанет работать, мы сможем получить новый токен и подставить его в скрипт. Протестировать возможности работы с Яндекс.Диском, используя полученный токен, можно на специальном полигоне.
А теперь сам bash-скрипт для бекапа на Яндекс.Диск:
#!/bin/bash
#
# Yandex.Disk backup script v1.0 by Sergey Lukonin (neblog.info)
#
# # # # # # # # # # НАСТРОЙКИ БЕКАПА MYSQL # # # # # # # # # #
# Сервер БД
MYSQL_SERVER=mysql.some-server.ru
# Юзер, под которым будем делать бекап доступных баз, руту mysql обычно доступны все БД, отдельному пользователю обычно доступна БД конкретного проекта
MYSQL_USER=some-user
# Пароль пользователя базы данных (Пароль от рута сервера и от рута mysql разные не путайте)
MYSQL_PASSWORD=some-password
# # # # # # # # # # ОБЩИЕ НАСТРОЙКИ # # # # # # # # # #
# Директория для временного хранения бекапов, которые удаляются после отправки на Яндекс.Диск
BACKUP_DIR='/home/www/backup'
# Название проекта, используется в логах и именах архивов
PROJECT='neblog.info'
# Максимальное количество хранимых на Яндекс.Диске бекапов (0 - хранить все бекапы):
MAX_BACKUPS='14'
# Дата, используется в именах архивов
DATE=`date '+%Y-%m-%d'`
# Директории для архивации (указываются через пробел), которые будут помещены в единый архив и отправлены на Яндекс.Диск
DIRS='/home/www/projects/neblog'
# Yandex.Disk токен (как получить - см. на neblog.info)
TOKEN=''
# Имя лог-файла, хранится в директории, указанной в $BACKUP_DIR
LOGFILE='backup.log'
# E-mail для отправки результата выполнения скрипта. Оставьте пустым, если отправлять результаты не требуется.
sendLog='your-mail@yandex.ru'
# Отправлять только ошибки (true). Укажите false, если нужно отправлять логи при любом результате выполнения скрипта.
sendLogErrorsOnly='false'
# # # # # # # # # # КОНЕЦ НАСТРОЕК # # # # # # # # # # # # #
# # # # # # # # ДАЛЬШЕ НИЧЕГО НЕ МЕНЯЕМ! # # # # # # # # # #
function mailing()
{
if [ ! $sendLog = '' ];then
if [ "$sendLogErrorsOnly" == true ];
then
if echo "$1" | grep -q 'error'
then
echo "$2" | mail -s "$1" $sendLog > /dev/null
fi
else
echo "$2" | mail -s "$1" $sendLog > /dev/null
fi
fi
}
function logger()
{
echo "["`date "+%Y-%m-%d %H:%M:%S"`"] File $BACKUP_DIR: $1" >> $BACKUP_DIR/$LOGFILE
}
function parseJson()
{
local output
regex="(\"$1\":[\"]?)([^\",\}]+)([\"]?)"
[[ $2 =~ $regex ]] && output=${BASH_REMATCH[2]}
echo $output
}
function checkError()
{
echo $(parseJson 'error' "$1")
}
function getUploadUrl()
{
json_out=`curl -s -H "Authorization: OAuth $TOKEN" https://cloud-api.yandex.net:443/v1/disk/resources/upload/?path=app:/$backupName&overwrite=true`
json_error=$(checkError "$json_out")
if [[ $json_error != '' ]];
then
logger "$PROJECT - Yandex.Disk error: $json_error"
mailing "$PROJECT - Yandex.Disk backup error" "ERROR copy file $FILENAME. Yandex.Disk error: $json_error"
echo ''
else
output=$(parseJson 'href' $json_out)
echo $output
fi
}
function uploadFile
{
local json_out
local uploadUrl
local json_error
uploadUrl=$(getUploadUrl)
if [[ $uploadUrl != '' ]];
then
echo $UploadUrl
json_out=`curl -s -T $1 -H "Authorization: OAuth $TOKEN" $uploadUrl`
json_error=$(checkError "$json_out")
if [[ $json_error != '' ]];
then
logger "$PROJECT - Yandex.Disk error: $json_error"
mailing "$PROJECT - Yandex.Disk backup error" "ERROR copy file $FILENAME. Yandex.Disk error: $json_error"
else
logger "$PROJECT - Copying file to Yandex.Disk success"
mailing "$PROJECT - Yandex.Disk backup success" "SUCCESS copy file $FILENAME"
fi
else
echo 'Some errors occured. Check log file for detail'
fi
}
function backups_list() {
# Ищем в директории приложения все файлы бекапов и выводим их названия:
curl -s -H "Authorization: OAuth $TOKEN" "https://cloud-api.yandex.net:443/v1/disk/resources?path=app:/&sort=created&limit=100" | tr "{},[]" "\n" | grep "name[[:graph:]]*.tar.gz" | cut -d: -f 2 | tr -d '"'
}
function backups_count() {
local bkps=$(backups_list | wc -l)
# Если мы бекапим и файлы, и БД, то на 1 бекап у нас приходится 2 файла. Поэтому количество бекапов = количество файлов / 2:
expr $bkps / 2
}
function remove_old_backups() {
bkps=$(backups_count)
old_bkps=$((bkps - MAX_BACKUPS))
if [ "$old_bkps" -gt "0" ];then
logger "Удаляем старые бекапы с Яндекс.Диска"
# Цикл удаления старых бекапов:
# Выполняем удаление первого в списке файла 2*old_bkps раз
for i in `eval echo {1..$((old_bkps * 2))}`; do
curl -X DELETE -s -H "Authorization: OAuth $TOKEN" "https://cloud-api.yandex.net:443/v1/disk/resources?path=app:/$(backups_list | awk '(NR == 1)')&permanently=true"
done
fi
}
logger "--- $PROJECT START BACKUP $DATE ---"
logger "Выгружаем дампы баз"
mkdir $BACKUP_DIR/$DATE
for i in `mysql -h $MYSQL_SERVER -u $MYSQL_USER -p$MYSQL_PASSWORD -e'show databases;' | grep -v information_schema | grep -v Database`;
do mysqldump -h $MYSQL_SERVER -u $MYSQL_USER -p$MYSQL_PASSWORD $i > $BACKUP_DIR/$DATE/$i.sql;
done
logger "Создаем архив mysql $BACKUP_DIR/$DATE-mysql-$PROJECT.tar.gz"
tar -czf $BACKUP_DIR/$DATE-mysql-$PROJECT.tar.gz $BACKUP_DIR/$DATE
rm -rf $BACKUP_DIR/$DATE
logger "Создаем архив каталогов $BACKUP_DIR/$DATE-files-$PROJECT.tar.gz"
tar -czf $BACKUP_DIR/$DATE-files-$PROJECT.tar.gz $DIRS
FILENAME=$DATE-mysql-$PROJECT.tar.gz
logger "Выгружаем на Яндекс.Диск архив mysql $BACKUP_DIR/$DATE-mysql-$PROJECT.tar.gz"
backupName=$DATE-mysql-$PROJECT.tar.gz
uploadFile $BACKUP_DIR/$DATE-mysql-$PROJECT.tar.gz
FILENAME=$DATE-files-$PROJECT.tar.gz
logger "Выгружаем на Яндекс.Диск архив с файлами $BACKUP_DIR/$DATE-files-$PROJECT.tar.gz"
backupName=$DATE-files-$PROJECT.tar.gz
uploadFile $BACKUP_DIR/$DATE-files-$PROJECT.tar.gz
logger "Удаляем архивы с диска"
find $BACKUP_DIR -type f -name "*.gz" -exec rm '{}' \;
# Удаляем старые бекапы с Яндекс.Диска (если MAX_BACKUPS > 0)
if [ $MAX_BACKUPS -gt 0 ];then remove_old_backups; fi
logger "Завершение скрипта бекапа"
Также вы можете скачать готовый файл скрипта. Скрипт следует расположить на сервере, заменить в нём параметры на свои, дать права на запуск (chmod +x) и поставить на ежедневное выполнение в cron. Если вы планируете выполнять несколько таких заданий, задайте время между их запуском (5-10 минут).
