Привіт усім! В даній статті ми розглянемо вирішення проблеми автоматизації створення резервних копій Web-сайтів встановлених на Linux-сервері (або на іншій Юнікс-подібній ОС) за допомогою Bash-скриптингу.

Проблема

При роботі з Web-серверами і встановленими на них сайтами часто виникає необхідність створення резервних копій. Але ручний ввід команд через SSH доволі-таки рутинне заняття. Тому пропоную переглянути просту реалізацію Bash-скрипта, який і буде виконувати рутинну роботу по створенню резервних копій файлів Web-сайту і його MySQL-бази даних.

Завдання

Необхідно визначитись які функції повинен виконувати скрипт. Себто, яку саме рутину він повинен автоматизувати:
  • в результаті виконання скрипта повинен бути створений єдиний файл-архів, в якому знаходяться усі вказані необхідні файли певного Web-сайту;
  • скрипт повинен “вміти” створювати резервну копію MySQL-бази даних, з якої за необхідності можна повністю відновити базу даних сайту і відповідно його роботу;
  • створювати копію дерева вихідного коду Web-сайту; вести журнал створення резервних копій;
  • поміщати резервну копію у вказану директорію файлової системи; створювати різні види архівів для кінцевого файлу бекапу.
Скрипт самостійно виконувати резервні копії звичайно не зможе — хтось повинен його запускати на виконання. Це може бути як користувач самостійно, так і система cron, яка автоматично у вказаний час буде запускати скрипт на виконання з необхідними параметрами.

Реалізація

Реалізація даного скрипта може виглядати наступним чином (Ви можете скопіювати його на свій жорсткий диск у локальний файл “site_backuper.sh”, за умовами ліцензії OpenBSD або скористатись посиланням https://github.com/yuriysydor1991/sites-backuper):
#
# Copyright (c) 2016 Yuriy Sydor <yuriysydor1991@gmail.com>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#

#!/bin/bash

# версія поточного скрипта
VERSION="1.0.0"

# змінні, які містять інформацію про підключення до локальної бази MySQL
mysql_db_name=
mysql_db_username=
mysql_db_password=

# директорія в якій буде міститись кінцевий файл бекапу
backup_dest_dir=
# тип файлу архіву
backup_archive_type=
# тип файлу по замовчуванню
default_archive_type="gz"
# файл журналу дій скрипта
backup_log_file=
# кінцева назва файлу бекапу
backup_name=
# директорія розміщення скриптів сайту
site_dir=

#тимчасова директорія в яку будуть акумулюватись файли бекапу
tmp_dir=

# доступні типи архіву
declare -A avail_archive_types
avail_archive_types["tar"]="cf"
avail_archive_types["gz"]="czf"
avail_archive_types["bz2"]="cjf"
avail_archive_types["xz"]="cJf"

# функція, яка виводить документацію по програмі і його версію
print_usage_and_exit ()
{
  echo -e "$0 v.$VERSION"
  echo -e "Program, that helps to create Web-site backups\n"
  echo -e "Usage:"
  echo -e "\n\t$0 [OPTIONS]"
  echo -e "\nWhere OPTIONS can be following:"
  echo -e "\n\t--dest-backup-dir[=]DIR "
  echo -e "\t\tSave backup file to destination directory DIR."
  echo -e "\t\tIf no directory specified - backup to home directory"
  echo -e "\n\t--db-info-mysql[=]DBINFO"
  echo -e "\t\tAdd to backup specified database dump from local MySQL server"
  echo -e "\t\tDBINFO must to have next syntax: DBNAME:DBUSER:DBPASSWORD"
  echo -e "\t\tWhere:"
  echo -e "\t\tDBNAME - MySQL local server database name needed to backup;"
  echo -e "\t\tDBUSER - MySQL local server database valid username;"
  echo -e "\t\tDBPASSWORD - MySQL local server username password."
  echo -e "\n\t--site-dir[=]DIR "
  echo -e "\t\tAdd to backup archive site source directory from directory DIR"
  echo -e "\n\t--archive-type[=]TYPE" 
  echo -e "\t\tBackup archive will be of type TYPE."
  echo -e "\t\tAvailable next archives types "
  echo -e "\t\t(if program tar installed on your host): "${!avail_archive_types[@]}"."
  echo -e "\n\t--backup-name[=]FILENAME"
  echo -e "\t\tdest backup filename will be FILENAME.TYPE"
  echo -e "\n\t--log[=]LOGFILE"
  echo -e "\t\tLog backuping process to log file LOGFILE.\n\t\tIf no log file specified - output all message to stdout"
  echo -e "\n Permission to use, copy, modify, and distribute this software for any"
  echo -e " purpose with or without fee is hereby granted, provided that the above"
  echo -e " copyright notice and this permission notice appear in all copies.\n"
  echo -e " THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES"
  echo -e " WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF"
  echo -e " MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR"
  echo -e " ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES"
  echo -e " WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN"
  echo -e " ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF"
  echo -e " OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE."
  echo -e "\n Copyright (c) 2016 Yuriy Sydor <yuriysydor1991@gmail.com>"
  
  exit 0 ;
}

# перевіряємо кількість переданих параметрів
if [[ $# -le 1 ]] ; then
  print_usage_and_exit
fi

# функція, яка при наявності вказаного файлу журналу, 
# записує повідомлення у нього, в іншому випадку
# виводить передані параметри на екран
log_message ()
{
  local form_msg=$(date +"%d.%m.%Y %H:%M:%S ")$*
  
  # якщо вказаний файл - робимо запис у нього
  # в іншому випадку виводимо запис в стандартний вивід
  if [[ -n $backup_log_file ]]
  then
    echo "$form_msg" >> "$backup_log_file"
  else
    echo "$form_msg"
  fi ;
}

# функція яка створює дамп локальної MySQL бази в поточну директорію
# перший параметр - назва бази даних
# другий - ім'я користувача, який має необхідні права 
# на використання бази (LOCK TABLES, SELECT і інші)
# третій параметр - пароль до вказаного користувача бази даних
# четвертий параметр - назва файлу дампу бази
make_mysql_dump ()
{
  if [[ -z $1 || -z $2 || -z $3 ]] ; then
    log_message "make_mysql_dump(): some connection data is not available - can\`t create dump"
    return 1
  fi
  
  dump_name=$4
  
  if [[ -z $dump_name ]] ; then
    dump_name="mysql_database_dump"
  fi
  
  # перевіряємо чи файл має закінчення ".sql"
  if [[ ! $dump_name = "*.sql" ]] ; then
    # якщо закінчення не існує - додаємо його
    dump_name="$dump_name".sql
  fi
  
  log_message "make_mysql_dump(): Trying to create MySQL database dump to file $dump_name"
  
  if [[ ! $(mysqldump --user="$2" --password="$3" --result-file="$dump_name" "$1") ]]
  then
    log_message "make_mysql_dump(): Fail to create database dump!!!"
    return 2
  fi
  
  log_message "make_mysql_dump(): Done to creating database dump"
}

# цикл розпізнавання переданих параметрів
for (( iter=$((1)) ; $iter<=$# ; ++iter ))
do
  
  # отримуємо позиційний параметр скрипта за номером iter
  param=${@:$iter:1}
  next_param=${@:$(($iter+1)):1}
  
  # перевіряємо, чи наступний параметр не подібний на прапорець
  if [[ $next_param = -* ]] ; then
    # якщо так - робимо змінну пустою
    next_param=
  fi
  
  # інтерпретуємо параметр який міститься в $param
  # не використовуємо вбудовану команду getopts,
  # оскільки вона не підтримує довгі прапорці
  case $param in
  
    --backup-name* | -backup-name*)
      
      #на випадок вказування даних після знаку "="
      if [[ "$param" = *=* ]] ; then
        backup_name=${param#*=}
      # на випадок вказування даних в якості окремого параметра
      elif [[ -n $next_param ]] ; then
        backup_name=$next_param
        # інкрементуємо ітератор поза охороною циклу
        # щоб цикл не сприймав дані прапорця в якості
        # іншого прапорця
        iter=$iter+1
      else
        echo -e "parameter must to have data: '$param'\n"
        print_usage_and_exit
      fi
      
      # замінюємо спеціальні символи в назві бекапу
      backup_name=$(date +"$backup_name")
    
      ;;
  
    --db-info-mysql* | -db-info-mysql*)
      
      #на випадок вказування даних після знаку "="
      if [[ "$param" = *=* ]] ; then
        mysql_db_name=${param#*=}
      # на випадок вказування даних в якості окремого параметра
      elif [[ -n $next_param ]] ; then
        mysql_db_name=$next_param
        # інкрементуємо ітератор поза охороною циклу
        # щоб цикл не сприймав дані прапорця в якості
        # іншого прапорця
        iter=$iter+1
      else
        echo -e "parameter must to have data: '$param'\n"
        print_usage_and_exit
      fi
      
      # отримуємо значення параметрів підключення до MySQL,
      # поступово видаляючи частини переданого рядка
      
      # видаляємо початок і кінець параметра для ім'я користувача 
      mysql_db_username=${mysql_db_name#*:}
      mysql_db_username=${mysql_db_username%:*}
      
      # видаляємо початок параметру з двома символами ":"
      # щоб отримати пароль з кінця
      mysql_db_password=${mysql_db_name##*:}
      
      # отримуємо ім'я бази даних, 
      # видаляючи кінець рядка з двома символами ":"
      mysql_db_name=${mysql_db_name%%:*}
      
      ;;
      
    --archive-type* | -archive-type*)
      
      #на випадок вказування шляху після знаку "="
      if [[ "$param" = *=* ]] ; then
        backup_archive_type=${param#*=}
      # на випадок вказування шляху в якості окремого параметра
      elif [[ -n $next_param ]] ; then
        backup_archive_type=$next_param
        # інкрементуємо ітератор поза охороною циклу
        # щоб цикл не сприймав дані прапорця в якості
        # іншого прапорця
        iter=$iter+1
      else
        echo -e "parameter must to have data: '$param'\n"
        print_usage_and_exit 
      fi
    
      ;;
  
    --site-dir* | -site-dir*)
      
      #на випадок вказування шляху після знаку "="
      if [[ "$param" = *=* ]] ; then
        site_dir=${param#*=}
      # на випадок вказування шляху в якості окремого параметра
      elif [[ -n $next_param ]] ; then
        site_dir=$next_param
        # інкрементуємо ітератор поза охороною циклу
        # щоб цикл не сприймав дані прапорця в якості
        # іншого прапорця
        iter=$iter+1
      else
        echo -e "parameter must to have data: '$param'\n"
        print_usage_and_exit 
      fi
      
      # робимо шлях до журналу канонічним на випадок
      # зміни поточної директорії командою cd
      site_dir=$(readlink -f $site_dir)
      
      ;;
      
    --dest-backup-dir* | -dest-backup-dir*)
    
      #на випадок вказування шляху після знаку "="
      if [[ "$param" = *=* ]] ; then
        backup_dest_dir=${param#*=}
      # на випадок вказування шляху в якості окремого параметра
      elif [[ -n $next_param ]] ; then
        backup_dest_dir=$next_param
        # інкрементуємо ітератор поза охороною циклу
        # щоб цикл не сприймав дані прапорця в якості
        # іншого прапорця
        iter=$iter+1
      else
        echo -e "parameter must to have data: '$param'\n"
        print_usage_and_exit 
      fi
      
      # робимо шлях до журналу канонічним на випадок
      # зміни поточної директорії командою cd
      backup_dest_dir="$(readlink -f $backup_dest_dir)"
      
      ;;
  
    --log* | -log*)
    
      # якщо шлях до журналу стоїть після знаку "="
      if [[ "$param" = *=* ]] ; then
        backup_log_file=${param#*=}
      # якщо шлях журналу являється наступним параметром
      elif [[ -n $next_param ]] ; then 
        backup_log_file=$next_param
        # інкрементуємо ітератор поза охороною циклу
        # щоб цикл не сприймав дані прапорця в якості
        # іншого прапорця
        iter=$iter+1 
      else
        echo -e "parameter must to have data: '$param'\n"
        print_usage_and_exit 
      fi
      
      # робимо шлях до журналу канонічним на випадок
      # зміни поточної директорії командою cd
      backup_log_file="$(readlink -f $backup_log_file)"
      
      ;;
      
    *)
      # "зловили" невідомий параметр - виводимо
      # документацію про використання програми
      # і завершуємо роботу
      echo -e "Unknown parameter: $param)\n"
      print_usage_and_exit 
      
      ;;
      
  esac
  
done

log_message "Start to creating backup of: $site_dir"

if [[ -z $mysql_db_name && -z $site_dir ]] ; then
  log_message "Directory or MySQL connection info must be supplied. Nothing to backup. Quiting!"
  exit 1
fi

# якщо не встановлене значення директорії
# розміщення файлу - встановлюємо її в домашню
# поточного користувача, який викликав скрипт
if [[ -z $backup_dest_dir ]] ; then
  backup_dest_dir=$(readlink -f ~)
  log_message "Didn\`t find --dest-backup-dir parameter, makeing it home: $backup_dest_dir"
fi

# визначаємо шлях для тимчасової папки бекапу
tmp_dir="$backup_dest_dir"/"$backup_name"

# на всякий випадок, перевіряємо чи tmp_dir не вказує на 
# кореневий каталог файлової системи, якщо так - вихід з скрипта, 
# оскільки директорія буде видалятися в майбутньому
if [[ $tmp_dir = "/" ]]; then
  log_message "Something realy bad happens: temporary directory points to $tmp_dir"
  log_message "QUIT!!!"
  exit 1
fi

# якщо тимчасова папка вже існує - видаляємо її
log_message "Checking if $tmp_dir already exists"
if [[ -d "$tmp_dir" ]] ; then
  log_message "Directory $tmp_dir already exists - erasing it"
  rm -fr "$tmp_dir"
fi

# спроба створити тимчасовий каталог
log_message "Trying to create temporary dir: $tmp_dir"
if [[ ! $(mkdir -v "$tmp_dir") ]] ; then
  log_message "Fail to create temporary directory: $tmp_dir"
  exit 2
fi

# змінні які індикують успішність створення бекапу бази
# і копіювання файлів скриптів
success_db_dump=
success_scripts_copy=

# якщо вказана назва бази даних MySQL - створюємо її дамп
if [[ -n "$mysql_db_name" ]] ; then
  log_message "Trying to create MySQL database dump"
  if [[ $(make_mysql_dump "$mysql_db_name" "$mysql_db_username" "$mysql_db_password" "${tmp_dir}/${backup_name}_mysql_dump") ]]
  then
    success_db_dump="Success"
  fi
else
  # якщо не вказана база даних - заповнюємо змінну індикатор
  success_db_dump="Not supplied"
  log_message "Database connection info doesn't supplied - skipping database dump"
fi

# якщо вказана директорія розміщення сайту -
# копіюємо її до тимчасової директорії розміщення даних бекапу
if [[ -n "$site_dir" ]] ; then
  log_message "Copying site scripts folder '$site_dir' to temporary directory"
  if ! $(cp -R "$site_dir" "$tmp_dir") ; then
    log_message "Fail to copy site folder script from path: $site_dir"
  else
    success_scripts_copy="Success"
  fi
else
  # якщо не вказана база даних - заповнюємо змінну індикатор
  success_scripts_copy="Not supplied"
  log_message "Scripts folder doesn't supplied - skipping backuping site scipts"
fi

# перевіряємо чи хоча б одна операція виконалась успішно
# якщо дві змінні-індикатори пусті - вихід з скрипта
if [[ -z $success_db_dump && -z $success_scripts_copy ]]
then
  log_message "Fail to create mysql dump and copy site scripts!!!"
  rm -fr "${tmp_dir}"
  exit 3
fi

# переміщуємось в папку призначення файлу
cd $backup_dest_dir

# перевіряємо параметри, які передаються команді tar
# якщо пусті - передаємо параметри для стандартного типу архіву
tar_opts=${avail_archive_types["${backup_archive_type}"]}
file_ext=tar."${backup_archive_type}"
if [[ -z $tar_opts ]] ; then
  tar_opts=${avail_archive_types[$default_archive_type]}
  file_ext=tar."${default_archive_type}"
fi

# якщо розширення "tar" вказано два рази
file_ext=${file_ext/tar.tar/tar}

# якщо успішно виконано хоча б одна операція - архівуємо тимчасову директорію
log_message "Trying to create backup files archive: ${backup_dest_dir}/${backup_name}.${file_ext}"
if ! $(tar "${tar_opts}" "$backup_name"."${file_ext}" "${backup_name}")
then
  log_message "Error while creating backup archive!!!"
  rm -fr "${tmp_dir}"
  exit 4
fi

log_message "Trying to erase temporary backup directory: $tmp_dir"
if ! $(rm -fr "$tmp_dir") ; then
  log_message "Fail to erase temporary directory"
fi

log_message "End"

exit 0
Як вказано в коді Bash-скрипта, він розповсюджується за ліцензією OpenBSD, що означає, що Ви можете розповсюджувати, модифікувати і використовувати його на свій розсуд. Коментарі в скрипті на українській, що полегшує моїм дорогоцінним співвітчизникам, і в майбутньому мені, розуміння і модифікування shell-коду. Слід пам'ятати, що даний скрипт не перевіряє простір, який займають створені ним файли резервних копій, тому він, через часті створення резервних копій, може заповнити файлову систему, що може призвести до відмови цілого серверу. Тому час від часу необхідно видаляти старі бекапи.

Використання

Ось так виглядає запуск скрипта без будь-яких параметрів: Bash_sscript_for_automation_backup_creating_output Документація по використанню даного скрипта виконана на англійській, щоб на сервері де командний інтерпретатор не сприймає вивід UTF-8 рядків, користувач все-таки зміг розібрати документацію. Як видно з виводу допомоги скрипта, йому можна передати шість різних параметрів:
  • --dest-backup-dir — вказує директорію призначення кінцевого архівованого файлу бекапу. Дана директорія також використовується в якості тимчасової директорії розміщення не архівованих файлів. Через даний параметр Ви можете вказати, наприклад, директорію у якій містяться файли приватного ftp-сервера, щоб мати змогу переглянути наявні файли резервних копій, і за необхідності завантажити нові чи видалити старі файли.
  • --db-info-mysql — якщо вказаний даний параметр скрипта, скрипт буде намагатись створити файл-дамп бази даних за допомогою команди mysqldump, яка повинна бути встановленою на комп'ютері, де розміщений скрипт. Параметри підключення до локальної бази MySQL передаються через рядок у вигляді НАЗВА_БАЗИ:КОРИСТУВАЧ:ПАРОЛЬ.
  • --site-dir — даний параметр вказує на директорію, вміст якої необхідно включити в результуючий бекап-файл. --archive-type — вказує на тип компресора, який потрібно використовувати при архівуванні результуючого файлу. Якщо не бажане використання будь-якого компресора необхідно вказати рядок “tar”. Якщо даний параметр не вказаний — скрипт використає стандартний компресор gzip і результуючий бекап-файл буде мати розширення “.tar.gz”.
  • --backup-name — ім'я фалу бекапу. Для даного параметру передається рядок, який містить назву результуючого бекап-файлу. Крім того, даний рядок може містити символи форматування дати, які сприймає команда date. Це зроблено для того, щоб при автоматичному створенні бекапу через систему cron, файл не перезаписувався, а кожного разу створювався новий, в назві якого вказано дату його створення.
  • --log — файл журналу скрипта. Шлях до файлу, переданий через даний параметр вказує на файл у який скрипт буде записувати хід створення бекапів. Даний скрипт не перевіряє розмір даного файлу журналу, тому слід час-від часу його перевіряти і за необхідності очищувати записи. Якщо даний параметр не вказано — скрипт виводить усі повідомлення на стандартний потік виводу програми. У випадку використання системи cron — даний вивід буде пересилатися в якості повідомлення користувачу під яким він запускається (якщо встановлена поштова програма на подобі postfix і якщо не виконано перенаправлення виводу).
Усі дані усіх прапорців можна вказати як через символ “=” (без використання пробілів між прапорцями і їхніми даними), або через пробіл (в якості окремого позиційного параметру). Також прапорці можливо вказувати через два або один символ тире “-”. Обов'язково необхідно вказати хоча б один з параметрів --site-dir або --db-info-mysql. В іншому випадку скрипт виведе повідомлення про помилку. Тепер розглянемо приклад створення повної резервної копії усього сайту, яка виконується за допомогою наступної команди (вважається, що вищенаведений скрипт знаходиться в поточній директорії і називається “site_backuper.sh”):
./sites_backuper.sh --dest-backup-dir "/home/crg" --site-dir="/var/www/html/wp2" --backup-name "site_backup_%d.%m.%Y_%H.%M.%S" --db-info-mysql "mysite:wordpress1:wordpress_password" --archive-type="xz"
Вивід скрипта наступний: bash_script_backup_maker_simple_backup_output В даному виклику скрипта ми вказали: результуючу директорію розміщення резервної копії сайту “/home/crg”; ім'я база даних — mysite, користувач wordpress1 і пароль wordpress_password; тип архіву “xz” — найкращий компресор (lzma) з найдовшою обробкою файлу (gzip компресор працює швидше, але і кінцевий файл архіву має більший розмір); директорія розміщення скриптів і інших файлів Web-сайту знаходяться у директорії /var/www/html/wp2, яка буде повністю включена в файл резервної копії; ім'я результуючого файлу буде мати наступний вигляд “site_backup_%d.%m.%Y_%H.%M.%S”, де %d - вказує на день запуску скрипта, %m — місяць, %Y — рік, %H — годину в 24-годинному форматі і %S — секунду відповідно (Тобто на місці даних сполучень символів підставляються відповідні значення за допомогою команди “date”).

Записи у crontab

Тепер для повної автоматичності створення бекапів, слід зробити відповідні записи у файлі /etc/crontab, який відповідає з періодичне виконання команд в Linux і інших Юнікс-подібних системах. Але перегляньте документацію для вашого дистрибутиву ОС — може виявитись, що пряме редагування даного файлу заборонене, натомість необхідно скористатися утилітою crontab наступним чином:
crontab -e
що викликає текстовий редактор з відкритим відповідним файлом cron, у який і необхідно ввести записи на використання скрипта “sites_backuper.sh”. На моїй GNU/Linux системі можна обійтись звичайним редагуванням файлу /etc/crontab.

Повне резервне копіювання сайту

Для автоматичного періодичного створення повної резервної копії сайту з періодом в 1 день слід скористатися наступним записом у файлі /etc/crontab:
@daily	crg	/bin/bash /home/crg/sites_backuper.sh --dest-backup-dir "/home/crg" --site-dir="/var/www/html/wp2" --backup-name "site_backup_%d.%m.%Y_%H.%M.%S" --db-info-mysql "mysite:wordpress1:wordpress_password" --archive-type="xz"
Замість рядка crg усюди потрібно вставити назву облікового запису, від імені якого необхідно виконувати резервне копіювання. Хоча в скрипті “sites_backuper.sh”, який на моїй машині знаходиться у директорії “/home/crg” (яку також необхідно замінити на відповідну директорію розміщення даного скрипта), вказаний рядок #!/bin/bash, демон crond все-одно може не запустити відповідний командний інтерпретатор (Bash), що може призвести до неправильної роботи скрипта, саме тому додактково, в якості команди, вказане виконання програми /bin/bash, якій і передається назва скрипта і усі його параметри. Рядок “@daily”, який розміщений на початку запису, вказує на періодичний запуск скрипта бекапу кожного дня в 0 годин і 0 хвилин.

Часткове резервне копіювання сайту

В попередньому прикладі ми створювали бекапи на початку кожного дня. А якщо ми бажаємо створювати резервні копії сайту набагато частіше, щоб забезпечити безпеку даних, введених користувачами протягом дня (у випадку сайту, який відвідують багато користувачів протягом дня). Якщо директорія сайту не змінюється або змінюється мало, внаслідок особливості побудови сайту, ми можемо розділити створення резервних копій на декілька частин: на першій стадії, яка виконується часто, наприклад, кожних 30 хвилин, відбувається створення бекапу бази даних; а на другій стадії відбувається резервне копіювання вмісту директорії розміщення коду сайту. За бажанням на першій стадії створення бекапу (бекап бази даних MySQL), можна також включати створення резервної копії директорії завантаження включень користувачів (фотографії і інші файли), яка має назву подібну до “uploads” або, у випадку CMS Wordpress вона знаходиться за шляхом “wp-content/uploads” відносно кореневої директорії розміщення сайту. Щоб виконати розділене створення резервних копій сайту, необхідно додати два наступних рядка до файлу /etc/crontab (на забувайте, що ви повинні мати права адміністратора, щоб редагувати даний файл):
*/30 *   * * *	crg	/bin/bash sites_backuper.sh --dest-backup-dir "/home/crg" --site-dir="/var/www/html/wp2/wp-content/uploads" --backup-name "kytok.org.ua_database_backup_\%d.\%m.\%Y_\%H.\%M.\%S" --db-info-mysql "mysite:wordpress1:wordpress_password" --archive-type="xz" --log="/home/crg/backuper.log"
@daily	crg	/bin/bash sites_backuper.sh --dest-backup-dir "/home/crg" --site-dir="/var/www/html/wp2" --backup-name "kytok.org.ua_scripts_backup_\%d.\%m.\%Y_\%H.\%M.\%S" --archive-type="xz" —log="/home/crg/backuper.log"
Відповідні рядки імені користувача, під яким необхідно запустити скрипт, усі шляхи до директорій (шлях до скрипта, шлях до цільових директорій і інші) і паролі бази даних потрібно замінити на власні. Перший рядок вказує на періодичне створення бекапу бази даних і дочірньої директорії uploads сайту кожні 30 хвилин, а другий - створення бекапу усього коду сайту на початку кожного дня (в нуль годин нуль хвилин).

Висновок

В даній статті ми створили простий скрипт автоматизації процесу створення резервних копій за допомогою командного інтерпретатора Bash, який встановлений практично в усіх популярних дистрибутивах GNU/Linux. Хорошого Вам коду!