Скрипт резервного копирования. О безопасности данных. Как убрать старые копии файлов, сохранив несколько последних

Способов резервного копирования превеликое множество, но лично для меня они имеют свои минусы из-за которых я не использую их. Проще написать несколько простых скриптов, например, с помощью так называемого bat-ника или PowerShell. В этой статье я расскажу, как можно настроить резервное копирование с помощью скриптов, я их комбинирую и создаю связки.

Схема резервного копирования

В большинстве случаев backup сводится к сохранение неких файл. Это могут образы виртуальных машин, файлы пользователей, бекап базы SQL, выгрузка информационной базы 1С:Предприятие и т.д. Правильнее все эти резервные копии файлов хранить в другом месте, это может быть , сетевая папка, внешний диск, ленточный накопитель, ftp и т.д. Из-за удобства я использую ftp сервер.

Давайте разберем схему как же это все происходит:

  1. Копируем или перемещаем их в папку для отправки в архив
  2. Проверяем папку на наличие в ней новых backup"ов
  3. Отправляем файлы в архив на FTP сервер
  4. Удаляем старые backup файлы

В первом пункте мы создали файлы, которые нам необходимо скопировать на наш FTP сервер. Теперь нам нужно скопировать их в папку, которую в свою очередь отправим на FTP. Для этого можно воспользоваться простой командой:

Copy "ПУТЬ_К_ИСХОДНОЙ_ПАПКЕ\* C:\Backup\

Выполнив эту команды все наши файлы будут скопированы C:\Backup\. Выполнять данную команду имеет смысл, если Вы собираете из разных мест Ваши backup"ы. Теперь нам понадобится скрипт, который будет проверять папку на появление новых файлов и отправлять их на FTP сервер. Создаем пустой файл backup.ps1 и в него записываем следующий скрипт.

$a = (Get-Host).UI.RawUI $a.WindowTitle = "Sync Folder To Ftp" $ftp = "ftp://АДРЕС_FTP_СЕРВЕРА/" $localDirectory = "C:\Backup" $user = "ИМЯ_ПОЛЬЗОВАТЕЛЯ" $pass = "ПАРОЛЬ" $webclient = New-Object System.Net.WebClient $webclient.Credentials = New-Object System.Net.NetworkCredential($user,$pass) $Files = Get-ChildItem $localDirectory | Where {$_.LastWriteTime -gt (Get-Date).AddDays(-1)} foreach ($File in $Files) { $LocalFile = $File.FullName Write-Host "Getting $File from $localDirectory" -Foreground "Red" $webclient.UploadFile($ftp + $File, $LocalFile) Write-Host "Puting $File to $ftp" -Foreground "Yellow" } Write-Host "Finished Sync to $ftp" -Foreground "Green"

Давайте разберем как же работает данный скрипт. Сначало задаются переменные, в которых указывается сервер, имя пользователя, пароль, исходная папка. Затем в строке $Files = Get-ChildItem $localDirectory | Where {$_.LastWriteTime -gt (Get-Date).AddDays(-1)} делается выборка всех файлов, у которых дата изменения больше (-qt) чем текущая дата минус 1 день. Здесь можете подкорректировать под Ваше расписание. Я резервное копирование делаю каждый день. Затем в цикле мы проходим по каждому файлу, удовлетворяющему условия и отправляем его на FTP сервер.

Дабы не занимать место на диске, я удаляю бекапы старше 30 дней. В принципе, после отправки на FTP их можно тут же удалять, я оставляю их только для того что, если они вдруг понадобятся не пришлось бы тратить время на скачивание их с FTP, да и лишняя копия backup"ов не помешает, мало ли что может случится с FTP. Так что если место Вам позволяет, рекомендую хранить их и на исходном сервере.

Для очистки папки я использую скрипт removeOldBackups.ps1

$fullTargetPath = "C:\Backup" $deleteFiles = Get-Childitem $fullTargetPath -Recurse | Where {$_.LastWriteTime -lt (Get-Date).AddDays(-30)} | Foreach { Remove-Item $_.FullName -Force -Recurse}

Крайне простой скрипт, поясню только одну строку Where {$_.LastWriteTime -lt (Get-Date).AddDays(-30)} | в этой строке сравнивается дата изменения файла с текущей датой минус 30 дней, под это сравнения попадут файлы у которых LastWriteTime меньше текущей даты минус 30 дней. При необходимости можете подправить под Ваши нужды.

Предисловие

Идея создания скрипта, который способен в несколько кликов сделать резервную копию сайта(все файлы + дамп базы данных), появилась в то время когда я работал над несколькими проектами, а разработку и тестирование вел на локальном веб-сервере. Еще тогда у меня стоял Денвер, который со временем сменил на более стремительно развивающийся локальный комбайн из веб-служб - OpenServer .

Проекты были посещаемые, поэтому сначала делалась локальная копия всего сайта, а уже после с ней можно было работать и экспериментировать, не допуская перебоев в работе живого проекта. Резервную копию делал так: логинился по SSH и паковал папку проекта архиватором 7Zip или TGZ, делал дамп при помощи mysqldump и скачивал все это добро через веб или SCP/WinSCP.

Сразу же лень дала о себе знать и возникла мысль о автоматизации: "было бы круто если бы все что я вбиваю в консоль делалось автоматом для каждого сайта, а от меня требовалось лишь несколько кликов". Первый поиск решения автоматизации SSH под Windows сразу ще привел меня к утилите, которую я уже давно использую для работы с файлами на серверах - .

Принцип работы скрипта резервного копирования

Итак, суть работы скрипта автоматизированного резервного копирования заключается в следующем:

  1. Читаем данные из ini-файла, где храним настройки для сайта (название, логин, пароль, аккаунт mysql...);
  2. Исходя из данных генерируем скрипт для WinSCP, который будет делать все нужные операции в консоли на сервере;
  3. Запускаем программу WinSCP, которая логинится на сервер и делаем резервную копию сайта+БД, а также архивирует все данные используя архиватор с высокой степенью сжатия - 7Zip или TAR+GZip;
  4. Скачиваем архив;
  5. Закрываем WinSCP и чистим логи + удаляем временно сгенерированный скрипт для WinSCP с командами;
  6. Готово! Нужна копия еще одного сайта? - GOTO 1!

Сайтов может быть не один, а несколько, поэтому предусмотрено использование множества ini-файлов с отдельными настройками для каждого сайта.

Все операции по обработке и управлению WinSCP будет производить скрипт. написанный на скриптовом языке bat-файлов под Windows. С помощью него также реализован простой консольный интерфейс, который позволяет производить все нужные операции.

Для данной задачи, исходя из ее простоты, вполне достаточно скриптового языка bat-файлов, но все же никто не мешает осуществить реализацию данной системы на Autoit или же на одном из языков программирования высокого уровня, таких как C#, Delphi и т.п.

Внимание! Скрипт актуален только в том случае, если у вас есть доступ к консоли сервера по SSH.

Интерфейс и меню резервного копирования

После запуска скрипта нам доступно простое меню:

Первый пункт (жмем 1 и ентер) - отвечает за процесс резервного копирования и отображает список доступных конфигурационных файлов-шаблонов для сайтов.

Второй пункт - генерация шаблона конфигурационного файла и открытие его для правки.

Третий пункт - краткая справка по написанию файлов-шаблонов.

На рисунке ниже открыто меню с выбором доступных к резервированию сайтов:

Здесь подпункт "0. All sites listed below" отвечает за запуск резервного копирования всех сайтов с нижеуказанными конфигурационными файлами. Так что можно сделать резервную копию для одного сайта или же для всех сразу.

Пример конфигурационного файла для скрипта

Вот пример конфигурационного файла somesite.com.ini для резервного копирования сайта somesite.com:

Sitename_string=somesite_com store_path=D:\Backup\ archive_method=7z archive_password=StrOngp@sswOrd hostname=000.111.222.333 ssh_user=root ssh_password=p@ssmetotheserver mysql_user=site1_user mysql_password=PZBkOyjMmxWgQHhd185g mysql_db_name=site1_db dirs_to_backup=/var/www/somesite.com/www/* /var/www/somesite.com/www/.htaccess

Как видите, все просто и ничего лишнего. Расскажу подробно про каждую строку настроек:

sitename_string - присваиваем внятное название сайта (только латиница и символ _ ).

store_path - путь на локальном компьютере, куда будет загружен архив с резервной копией.

archive_method - метод архивации файлов сайта.

  • 7z - будет использован одноименный архиватор, на выходе получим архив с расширением "zip" .
  • gz - архивация при помощи TAR+GZip, на выходе получится архив с расширением "tgz" .

archive_password - пароль на архив, работает только когда archive_method=7z .

hostname - внешний IP адрес или домен сервера, на котором хостится сайт и БД.

ssh_user - имя пользователя для подключения по SSH . В большинстве случаев для выполнения всех операций нужен root, хотя можно попробовать настроить для другого непривилегированного пользователя.

ssh_password !! - пароль для вышеуказанного пользователя.

mysql_user * - имя пользователя для подключения к БД сайта на MySQL сервере.

mysql_password - пароль для вышеуказанного MySQL пользователя. Должен быть установлен обязательно !

mysql_db_name - название базы данных сайта, для которой будем делать полный дамп.

dirs_to_backup ** - пишем через пробел список полных путей, директорий и файлов, которые нужно архивировать.

Примечания:

Если оставить значение пустым то пароль будет запрошен потом в интерактивном режиме (рекомендую не хранить пароль).

* Предполагается что скрипты и база данных MySQL размещены на одном и том же сервере. То есть адрес MySQL-сервера - 127.0.0.1 (localhost).

** По умолчанию архиваторы не пакуют файлы.htaccess, поэтому нужно дополнительно указывать к ним полный путь!

** Указывать обязательно полные, а не относительные пути к папкам или файлам.

Создавать конфигурационных файлов можно сколько угодно, при запуске скрипта название каждого будет выведено с присвоенным номером, для начала работы нужно ввести номер(число) конфигурации и все (если не указали пароль - то введете еще пароль).

Подготовка к работе и использование скрипта

Все очень просто!

Первым делом нужно определиться где мы будем хранить скрипт со всеми его конфигурациями. Рекомендую не хранить подобные программы и данные на локальной машине в открытом виде, потому что это не безопасно, тем более если в конфигурациях будут сохранены пароли для root доступа к серверам. Комплекс можно хранить где-нибудь на зашифрованном носителе или там, куда не получат доступ вирусы или посторонние люди. В плане безопасности - выбор за вами, идем дальше.

Пусть весь комплекс будет располагаться по пути:

  • D:\Backup\ - сюда будут загружаться архивы с резервными копиями.
  • D:\Backup\script\ - здесь будет лежать наш скрипт и программа WinSCP.

1) Скачиваем последнюю настроенную и портабельную версию программы WinSCP с сайта PortableApps - WinSCP Portable . Устанавливаем программу в папку D:\Backup\script\ - там создастся папка WinSCPPortable , а в ней будет файл WinSCPPortable.exe .

2) Скачиваем архив со скриптом и шаблонами вот тут - backup_sites_v1.2 и распаковываем его в папку D:\Backup\script\ .

3) Открываем файл backup_sites_v1.2.bat для редактирования и правим в секции "WinSCP configuration" пути:

  • "D:\Backup\script\WinSCPPortable\WinSCPPortable.exe" - путь к программе WinSCP Portable;
  • "D:\Backup\script\WinSCPPortable\Data\settings\winscp.log" - путь по которому создается лог-файл программы WinSCP Portable.

Смотрим чтобы пути, прописанные в скрипте соответствовали тем, по которым находится программа WinSCP, иначе она просто не запустится.

4) Создаем файлы-шаблоны настроек для резервного копирования сайтов. В архиве их несколько - переименуйте их соответственно названиям доменов ваших сайтов, а лишние удалить.

Создать новый шаблон сайта для скрипта можно ткими способами:

  1. Просто копируем INI-файл, переименовав его под нужным названием, а потом правим в нем настройки;
  2. Генерируем шаблон скриптом. Запускаем скрипт, жмем 2 и вводим имя домена или название сайта (только латиница и символ _ ). Откроется блокнот с ново созданным файлом, после внесенных изменений сохраните его и закройте.

Какой вариант удобнее - выбирайте сами.

5) Все готово, можно запускать скрипт и пробовать делать резервную копию одного из своих сайтов.

После подтверждения выбора сайта для бекапа может быть запрошен пароль пользователя SSH, в случае если он не был указан в конфигурационном файле. Сразу же запустится окно с логом работы программы WinSCP, в котором будет отображен ход действий на сервере, а также прогресс скачивания готового архива с сервера.

Когда WinSCP завершит скачивание архива то окно закроется, чтобы завершить работу скрипта достаточно нажать в окне любую клавишу.

О безопасности данных

Скрипт в процессе своей работы генерирует временный файл ".tmp" с набором команд для WinSCP. В этом файле присутствует логин и пароль для доступа к серверу по SSH.

В INI-шаблонах с настройками сайтов также содержится важная информация - это параметры доступа к БД.

Настоятельно НЕ рекомендую хранить данный скрипт и файлы настроек на дисках, к которым можно получить прямой доступ в любой момент после запуска и несложных манипуляций с компьютером. Для хранения можно сделать шифрованный диск или же купить отдельный носитель.

Данный скрипт - это лишь инструмент, который экономит время на выполнении рутинных и похожих действий. Выделите время и побеспокойтесь о сохранности и безопасности своих данных!

Вся ответственность за использование данного скрипта возлагается на вас, будьте предельно внимательны!

Заключение

Скрипт можно откорректировать и доработать чтобы он стал более функционален и проделывал те действия, которые вам нужны на ваших сайтах.

Также данный способ автоматизации WinSCP можно использовать для построения других скриптов, которые будут выполнять разные задачи на вашем VPS или Dedicated сервере через консоль.

Обновлено: 21.07.2017 Опубликовано: 15.08.2016

Данный скрипт написан на Unix Shell под управлением операционной системы CentOS . Он будет работать на большинстве систем семейств Linux и BSD.

Пример скрипта

Скрипт будет создавать для каждой базы свой дамп. Это необходимо для быстрого восстановления данных.

  1. #!/bin/bash
  2. PATH=/etc:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
  3. destination="/backup/mysql"
  4. userDB="backup"
  5. passwordDB="backup"
  6. fdate=`date +%Y-%m-%d`
  7. find $destination -type d \(-name "*-1[^5]" -o -name "*-?" \) -ctime +30 -exec rm -R {} \; 2>&1
  8. find $destination -type d -name "*-*" -ctime +180 -exec rm -R {} \; 2>&1
  9. mkdir $destination/$fdate 2>&1
  10. for dbname in `echo show databases | mysql -u$userDB -p$passwordDB | grep -v Database`; do
  11. case $dbname in
  12. information_schema)
  13. continue ;;
  14. mysql)
  15. continue ;;
  16. performance_schema)
  17. continue ;;
  18. test)
  19. continue ;;
  20. *) mysqldump --databases --skip-comments -u$userDB -p$passwordDB $dbname | gzip > $destination/$fdate/$dbname.sql.gz ;;
  21. done;

Описание скрипта

1 Указываем на путь к интерпретатору.
2 Задаем системные переменные, чтобы не пришлось в скрипте прописывать полные пути до исполняемых файлов.
4 - 7 Задаем переменные.
4 Каталог, в котором будем сохранять резервные копии.
5 Учетная запись для подключения к базе данных.
6 Пароль для подключения к базе данных.
7 Дата, когда запускается скрипт.
9 Находим все резервные копии, которые старше 30 дней и удаляем их. Оставаляем для архива файлы на 15 число.
10 Удаляем все резервные копии старше 180 дней.
11 Создаем каталог, в который будем сохранять резервные копии. В качестве имени каталога используем дату запуска скрипта в формате ГГГГ-MM-ДД.
13 - 25 Подключаемся к базе данных и вытаскиваем список всех баз данных. Для каждой делаем резервную копию.
15 - 22 Пропускаем служебные базы information_schema, mysql, performance_schema, test.
23 Делаем резервную копию для баз.

Подготовка системы

Подключаемся к базе данных и создаем учетную запись с правом на создание резервных копий:

> GRANT SELECT, SHOW VIEW, RELOAD, REPLICATION CLIENT, EVENT, TRIGGER, LOCK TABLES ON *.* TO backup@localhost IDENTIFIED BY "backup";

* в данном примере мы создаем учетную запись backup с паролем backup .

Создаем каталог, в котором будут храниться резервные копии:

mkdir -p /backup/mysql

Сохранение данных на удаленном компьютере

Резервные копии необходимо создавать на удаленном компьютере или внешнем диске, чтобы они были доступны при выходе из строя сервера. В данном примере используется общая папка на удаленном сервере, в которой будут размещаться файлы с backup.

Чтобы упростить процесс монтирования сетевой папки, откроем на редактирование следующий файл:

и добавим в него следующую строчку:

//192.168.0.1/backup /mnt cifs user,rw,noauto,credentials=/root/.smbclient 0 0

* в данном примере выполняется монтирование общей папки backup на сервере с IP-адресом 192.168.0.1 в каталог /mnt . В качестве сетевой файловой системы используется cifs (протокол SMB: сервер samba или общая папка Windows). Параметры для подключения — user : позволяет выполнить монтирование любому пользователю, rw : с правом на чтение и запись, noauto : не монтировать автоматически при старте системы, credentials : файл, в котором написаны логин и пароль для подключения к общей папке.

Теперь создадим файл с логином и паролем:

# vi /root/.smbclient

и приведем его к следующему виду:

username=backup
password=backup

* username : имя пользователя, password : пароль. Само собой, в вашем случае указываются свои данные.

Теперь введите следующую команду.

Бэкап важной информации - каждый системный администратор сталкивается с такой задачей. Задача казалось бы тривиальная и у многих читателей интереса не вызовет. Но, например, мне бы такая статья в определенный момент помогла бы весьма сильно, поэтому считаю, что этой статье быть.

Задача: Бэкап данных в локальную директорию и на отдельный сервер, с использованием минимума стороннего ПО, логированием и оповещением администратора в jabber при сбоях. Все основные функции большинства ПО для автоматического бэкапа, но без установки оного, а следовательно без его багов (что, собственно, и привело к подобной идее).

А теперь к делу.

Для начала создадим и откроем скрипт
nano backup-script
Теперь в скрипте добавим строку
#!/bin/bash
Объявим некоторые переменные.
TN - TASKNAME - имя задания.Используется для вывода в лог и определения названия файла.
Так как заданий несколько (ежемесячное, еженедельное, ежедневное) и писать на каждый случай скрипт было лень, я создал универсальный, в котором надо просто раскомментить нужные строки. Наименование заданий писать надо без пробелов, желательно в латинице, если не хотите проблем с кодировкой и неправильными параметрами команд.
TN=docs-monthly
#TN=docs-weekly
#TN=docs-daily
OF - Output File - имя выходного файла. Получается из переменной TN, то есть имени задания.
OF=$TN.tar.gz
Объявляем переменную с путем к файлу лога, и далее все сообщения об ошибках и остальном будем выводить в лог.
LOGFILE=/var/log/backup.log
Сделаем запись в лог о начале бэкапа (дата, время, имя задания)
echo >>$LOGFILE echo "=====================================================" >>$LOGFILE echo "$(date +"%d-%b-%Y %R")" >>$LOGFILE echo "Задание \"$TN\" запущено..." >>$LOGFILE
Есть проблема в том что если указывать в параметрах команд (напр. tar) имена каталогов с пробелами, скрипт срабатывает с ошибкой. Решение найдено на просторах интернета - операционная система linux использует пробел в качестве стандартного разделителя параметров команды. Переопределим стандартный разделитель (хранится в переменной $IFS) отличным от пробела, например \n – знаком переноса строки.
Запоминаем старое значение стандартного разделителя
OLD_IFS=$IFS
Заменяем стандартный разделитель своим
IFS=$"\n"
SRCD - SouRCe Directory - каталог с данными для бэкапа
Теперь можно перечислять несколько каталогов, разделителем будет перенос строк как мы сами указали строкой выше
SRCD="/mnt/source/folder_1 /mnt/source/folder_2 /mnt/source/folder_N"
TGTD - TarGeT Directory - каталог в который будут складываться бэкапы
TGTD="/var/backups/"
Естественно мы понимаем что хранить важные бэкапы только на источнике как минимум легкомысленно. Поэтому оставим копию и на удаленном ресурсе, который будем отдельно монтировать с помощью mount и fstab. Сразу поясню почему я использовал mount и fstab, а не один mount - я монтирую этот каталог и в других своих скриптах, а как сказал один из знакомых программистов - хороший программист не будет писать один и тот же код дважды (как-то так, дословно не помню, но надеюсь смысл донес).
TGTD2="/mnt/archive/"
Сам процесс архивирования в варианте "Создать новый архив"
tar -czf $TGTD$OF $SRCD &>>$LOGFILE
и в варианте "Обновить файлы в старом архиве"
tar -u -f $TGTD$OF $SRCD &>>$LOGFILE
Во втором случае лучше вместо $OF использовать конктретное имя файла потому что у меня например ежедневно апдэйтится еженедельный архив, а их $TN (имена задания) не совпадают, соответственно и $OF.

В переменной "?" ханится статус выполнения последней команды. Сохраним его, чтобы воспользоваться позже.
STATUS=$?
Возвращаем стандартный разделитель к исходному значению
IFS=$OLD_IFS
Теперь добавим условие - если процесс упаковки в архив tar закончился с ошибкой, отправляем сообщение админу, удаляем неудачный файл бекапа. Иначе продолжаем дальше - монтируем сетевую шару и кидаем в нее копию архива. После каждой операции проверяем результат выполнения, пишем логи, и либо продолжаем, либо извещаем админа и прерываем процедуру.
if [[ $STATUS != 0 ]]; then rm $TGTD$OF &>>$LOGFILE echo "###########################################" >>$LOGFILE echo "### Произошла ошибка! Бэкап не удался. ###" >>$LOGFILE echo "###########################################" >>$LOGFILE echo "$(date +"%d-%b-%Y %R%nФайл") бекапа $OF не создан" | sendxmpp -t -f /usr/local/etc/XMPP_settings логин_получателя@домен &>>$LOGFILE else echo "Файл бэкапа сохранен как \"$TGTD$OF\"" >>$LOGFILE echo "Бэкап успешно завершен в $(date +"%R %d-%b-%Y")!" >>$LOGFILE echo "Монтирование файловой системы для резервного архива $TGTD_archive" >>$LOGFILE mount $TGTD2 &>>$LOGFILE if [[ $? != 0 ]]; then echo "#############################################################" >>$LOGFILE echo "### Произошла ошибка при монтировании резервного ресурса ###" >>$LOGFILE echo "#############################################################" >>$LOGFILE echo "$(date +"%d-%b-%Y %R%nФайл") бекапа $OF не скопирован на резервный ресурс" | sendxmpp -t -f /usr/local/etc/XMPP_settings логин_получателя@домен &>>$LOGFILE exit fi echo "Начато копирование файла на резервный ресурс" >>$LOGFILE cp -f $TGTD$OF $TGTD_archive$OF &>>$LOGFILE if [[ $? != 0 ]]; then echo "#############################################################" >>$LOGFILE echo "### Произошла ошибка при копировании на резервный ресурс ###" >>$LOGFILE echo "#############################################################" >>$LOGFILE echo "$(date +"%d-%b-%Y %R%nФайл") бекапа $OF не скопирован на резервный ресурс" | sendxmpp -t -f /usr/local/etc/XMPP_settings логин_получателя@домен &>>$LOGFILE else echo "Копирование файла успешно завершено в $(date +"%R %d-%b-%Y")!" >>$LOGFILE echo "Файл скопирован как \"$TGTD_archive$OF\"" >>$LOGFILE fi echo "Размонтирование файловой системы для резервного архива $TGTD_archive" >>$LOGFILE umount $TGTD2 &>>$LOGFILE echo "Все операции завершены успешно!" >>$LOGFILE fi exit

В процессе мы копируем архив из локального хванилища в удаленное. Естественно, проверяем, что каждая операция успешно завершена, и пишем все в логи.
Для отсылки сообщения администратору я использую XMPP сообщение, так как в организации поднят Jabber-сервер, и я больше люблю получить быстрое сообщение о сбое, чем лезть в почту, вбивая пароли, тыкая на ссылки, и ожидая пока браузер мне все отобразит. В любом случае никто не мешает вам использовать sendmail вместо sendxmpp.
Файл /usr/local/etc/XMPP_settings следующего содержания:

#логин_отправителя@домен;IP_jabber_сервера:порт_jabber_сервера пароль_отправителя login@domen;127.0.0.1:5222 password
В файле fstab строка описывающая подключение шары Windows
//192.168.0.250/arhiv /mnt/archive cifs noauto,rw,iocharset=utf8,cp866,file_mod=0666,dir_mod=0777,noexec,_netdev,credentials=/root/.passwd_to_archive_directory 0 0
Теперь осталось только добавить задание в cron. Это можно сделать с помощью файла /etc/crontab, но я, в силу привычки к GUI, оставшейся в наследство от виндовс, пользую вэб-интерфейсы для таких случаев. Команда должна выполняться с правами рута, то бишь, к примеру, sudo bash backup_script. Добавляя команду в cron можно определить что она будет сразу выполняться от имени root`а

В ходе обсуждений затронули проблему разрастания логов. Пошел по простейшему (на мой взгляд) пути: будем хранить только последние N строк лога, например 300. В скрипт добавятся две строки, в которых мы сохраним последние 300 строк лога во временный файл, потом затрем им лог
tail -n 300 $LOGFILE >/tmp/unique_fantastic_filename.tmp mv -f /tmp/unique_fantastic_filename.tmp $LOGFILE
Приведу полный текст скрипта:
#!/bin/bash TN=docs-monthly #TN=docs-weekly #TN=docs-daily OF=$TN.tar.gz LOGFILE=/var/log/backup.log echo >>$LOGFILE echo "=====================================================" >>$LOGFILE echo "$(date +"%d-%b-%Y %R")" >>$LOGFILE echo "Задание \"$TN\" запущено..." >>$LOGFILE OLD_IFS=$IFS IFS=$"\n" SRCD="/mnt/source/folder_1 /mnt/source/folder_2 /mnt/source/folder_N" TGTD="/var/backups/" TGTD2="/mnt/archive/" tar -czf $TGTD$OF $SRCD &>>$LOGFILE #tar -u -f $TGTD$OF $SRCD &>>$LOGFILE STATUS=$? IFS=$OLD_IFS if [[ $STATUS != 0 ]]; then rm $TGTD$OF &>>$LOGFILE echo "###########################################" >>$LOGFILE echo "### Произошла ошибка! Бэкап не удался. ###" >>$LOGFILE echo "###########################################" >>$LOGFILE echo "$(date +"%d-%b-%Y %R%nФайл") бекапа $OF не создан" | sendxmpp -t -f /usr/local/etc/XMPP_settings логин_получателя@домен &>>$LOGFILE else echo "Файл бэкапа сохранен как \"$TGTD$OF\"" >>$LOGFILE echo "Бэкап успешно завершен в $(date +"%R %d-%b-%Y")!" >>$LOGFILE echo "Монтирование файловой системы для резервного архива $TGTD_archive" >>$LOGFILE mount $TGTD2 &>>$LOGFILE if [[ $? != 0 ]]; then echo "#############################################################" >>$LOGFILE echo "### Произошла ошибка при монтировании резервного ресурса ###" >>$LOGFILE echo "#############################################################" >>$LOGFILE echo "$(date +"%d-%b-%Y %R%nФайл") бекапа $OF не скопирован на резервный ресурс" | sendxmpp -t -f /usr/local/etc/XMPP_settings логин_получателя@домен &>>$LOGFILE exit fi echo "Начато копирование файла на резервный ресурс" >>$LOGFILE cp -f $TGTD$OF $TGTD_archive$OF &>>$LOGFILE if [[ $? != 0 ]]; then echo "#############################################################" >>$LOGFILE echo "### Произошла ошибка при копировании на резервный ресурс ###" >>$LOGFILE echo "#############################################################" >>$LOGFILE echo "$(date +"%d-%b-%Y %R%nФайл") бекапа $OF не скопирован на резервный ресурс" | sendxmpp -t -f /usr/local/etc/XMPP_settings логин_получателя@домен &>>$LOGFILE else echo "Копирование файла успешно завершено в $(date +"%R %d-%b-%Y")!" >>$LOGFILE echo "Файл скопирован как \"$TGTD_archive$OF\"" >>$LOGFILE fi echo "Размонтирование файловой системы для резервного архива $TGTD_archive" >>$LOGFILE umount $TGTD2 &>>$LOGFILE echo "Все операции завершены успешно!" >>$LOGFILE fi tail -n 300 $LOGFILE >/tmp/unique_fantastic_filename.tmp mv -f /tmp/unique_fantastic_filename.tmp $LOGFILE exit

Всем спасибо за внимание!

Резервное копирование должно быть таким, чтобы Вы в любой момент могли сменить хостера и переехать на новый сервер. Поэтому весь процесс создания архивов должен быть автоматизирован. А файлы бэкапов должны лежать в надежном месте с возможностью круглосуточного доступа из любой точки планеты.

Публикую очередное решение по резервному копированию вебсервера. Этот bash скрипт создает единый архив базы данных и всех файлов сайта. Для удобства на диске локально хранится 30 последних резервных копий. А для надежности архивы резервных копий выкладываются на облачное хранилище Яндекс.Диск .
Подобных решений полно в сети. Но данный скрипт наиболее полно отражает мое видение резервного копирования web-серверов.

Основные принципы резервного копирования

Архивы делаем встроенными средствами операционной системы, чтобы облегчить процесс создания архива и ускорить восстановление сайта на новом сервере при необходимости.
Используем форматы архивом, которые позволяют сохранить все атрибуты файлов и папок. Чтобы получить точную копию сайта на новом месте.
Отдельно архивируем со сжатием базу данных и директорию веб-сервера со всеми файлами. А потом объединяем в единый архив уже без сжатия. Имя архива для удобства формируем на основании имени домена и даты его создания.
Организуем локальное хранилище из 30-ти последний архивных копий. Чтобы была возможность «откатить» сайт в предыдущее состояние на случай непредвиденных ситуаций. К примеру при заражения вирусами. Или неудачном обновлении CMS.
Организуем независимое хранилище резервных копий в облачном хранилище Яндекс.Диск и выкладываем туда наши архивы.

BASH скрипт резервного копирования файлов сайта и базы данных MySQL

#!/bin/bash # #ver 1.0 #2013-09-09 # #Переменные Базы данных DBHOST="localhost" #Адрес MySQL сервера DBUSER="bd_user" #Имя пользователя базы данных DBPASS="dBpAsS" #Пароль пользователя базы данных DBNAME="db_name" #Имя базы данных DBARC=$DBNAME.sql.gz #Имя архива базы данных # #Переменные WEBDAV WEBDAVURL="https://webdav.yandex.ru/backup/" #Адрес Яндекс.Диск. Папка должна существовать! WEBDAVUSER="[email protected]" #Имя пользователя от Яндекс.Диска (Яндекс.Почты) WEBDAVPASS="MyPasWordAtYandexMail" #Пароль от Яндекс.Диска # #Переменные сайта SCRIPTDIR="/home/serveruser/backup/" #Абсолютный путь откуда запускается скрипт и где храняться архивы SCRDIR="/home/serveruser/web/mydomain.com/public_html/" #Абсолютный путь к сайту от корня диска SCREXCLUDE="webstat" #Что не попадет в архив SCRARC="public_html.tar.gz" #Имя архива файлов сайта # #Переменные Резерных копий ARCNAME="mydomain.com"=$(date "+%F(%H:%M)")".tar" #Имя архивной копии сайта ARCMAX="30" #Количество файлов в локальном хранилище # #Переходим в корневую директорию вебсервера cd $SCRDIR # #Создаем файловый архив со сжатием, учитываем исключения tar cfz $SCRIPTDIR$SCRARC --exclude=$SCREXCLUDE * # #Возвращаемся в папку со скриптом, где лежат все архивы cd $SCRIPTDIR # #Архивируем базу данных со сжатием mysqldump -h$DBHOST -u$DBUSER -p$DBPASS $DBNAME | gzip > $DBARC # #Объединяем файловый архив и дамп базы данных, теперь уже без сжатия tar cf $SCRIPTDIR$ARCNAME $SCRARC $DBARC # #Отправляем результат в Яндекс.Диск curl --user $WEBDAVUSER:$WEBDAVPASS -T $ARCNAME $WEBDAVURL # #Убираем промежуточные архивы rm *.gz # #Удаляем старые копии сайта, оставляем несколько свежих копий ls -t *.tar | tail -n+$ARCMAX | xargs rm -f

Теперь разберем скрипт по полочкам. С переменными указанными в начале скрипта все понятно. Я постарался максимально отделить мух от котлет и все необходимое прокомментировал.
Перейдем к исполняемой части скрипта.

Как создать архив файлов сайта

C созданием архива проблем, как правило, нет. Главное не запутаться с абсолютными и относительными путями. Чтобы быть уверенными, что вы архивируете и где сохраняете.
Чтобы избежать полных абсолютных путей в архиве предварительно перейдем в корневую директорию сайта.

Я так не люблю, раскрываешь архив, а там папка home , заходишь в нее, а там еще одна, ты в нее, за ней следующая и так далее, короче матрешка. Замучаешься до содержимого добираться.
Поэтому перед созданием архива выполним команду:

Cd $SCRDIR

Тогда в архиве будет сразу содержимое корневой директории сайта безо всяких папок и подпапок. Примерно так:


Если у Вас есть файлы, которым не обязательно быть в резервной копии сайта, у меня это папка webstat , тогда необходимо настроить параметр —exclude.

Подробнее о всех параметрах tar можно почитать в официальном мануале .

Как создать резервную копию базы данных MySQL

Для получения дампа базы данных нам понадобятся параметры доступа к ней. Все они описаны в переменных скрипта и не должны вызвать затруднений. Для уменьшения размера файла сжимаем вывод утилиты mysqldump . Я использую gzip , который в *NIX-ах присутствует по-умолчанию.
Если у Вас используется старая версия MySQL сервера, до 4.1, то на базах большого объема может пригодиться параметр —quick . Использование которого указывает команде mysqldump сразу писать дамп базы на диск, а не кэшировать его в памяти. В более свежих версиях этот параметр включен по-умолчанию.

Единый файл резервных копий сайта

Чтобы решение было изящным, объединим два архива файлов сайта и дампа базы данных в один архив. Только теперь уже без сжатия, так как каждый из них мы их предварительно пропустили через gzip .
Для удобства имя файла составим из имени используемого домена и времени создания.

Как сохранить резервную копию сайта в Яндекс.Диск

В качестве облачного хранилища совсем не обязательно должен выступать Яндекс.Диск . Вы можете использовать, к примеру, Microsoft SkyDrive или любой другой сервис, использующий для доступа протокол WebDAV.

Как убрать старые копии файлов, сохранив несколько последних

В конце скрипта уберем ненужные файлы, это архивы файлов и базы данных и ограничим количество архивный копий сайта.
Осуществим поиск устаревших резервных копий и при наличии таковых их удалим. За это отвечает нижеследующий код:

Ls -t *.tar | tail -n+$MAXARC | xargs rm -f

Как это работает? По команде ls ищутся архивы (файлы с расширением tar ), вывод формируется по времени создания файла. Далее команда tail фильтрует список вырезая из него 30 первых. А остаток передается команде rm на удаление. Параметр f у нее служит для «молчания» в случае, если нечего удалять. Такое бывает, когда Вы только начали собирать резервные копии и их число не превышает значение переменной $MAXARC .
По совести говоря, после выполнения данной команды в «живых» останется только 29 резервных копий.

Запуск скрипта резервного копирования

Сохраняем скрипт, к примеру backup.sh . И присваиваем ему права на исполнение:

#chmod +x backup.sh

Удобнее всего использовать CRON для запуска скрипта по расписанию. Я создаю резервные копии раз в сутки в часы наименьшей нагрузки, то есть во второй половине ночи под утро.
Не забываем про владельцев папок и файлов, когда будем запускать скрипт на исполнение. Ведь файлы пользователя VASYA будут недоступны, если запустить скрипт от имени пользователя PETYA.

Результаты работы скрипта резервного копирования


Каждый день в 6 утра на сервере создается резервная копия сайта (файлы плюс база данных) и отправляется в облачное хранилище Яндекс.Диск .
При написании статьи в качестве тестовой площадки выступал реальный сервер, на котором работает этот блог. На сервере используется CentOS 6.4 со всеми обновлениями на начало сентября 2013.
Замечания и пожелания по работе скрипта приветствуются. В планах реализовать ограничение по количеству резервных копий не только на сервере, но и в облаке Яндекс.Диск . Пока же накопившееся со временем архивы приходится вычищать вручную.