Найти в Дзене
Типичный Админ

Скрипт для бэкапа почтовых ящиков Zimbra

Устроившись на новую работу, я получил в своё владение работающий настроенный сервер Zimbra версии 8.8.15_GA_3847. Работает этот сервер на виртуальной машине, и бэкапирование делается двумя методами: 1. бэкапится сама виртуальная машина
2.1. бэкапятся почтовые ящики всех пользователей раз в неделю
2.2. бэкапятся почтовые ящики некоторых избранных пользователей по будням. Про бэкап виртуальной машины всё понятно. А вот бэкапы почтовых ящиков делаются скриптами. Предыдущий системный администратор, скорее всего, скрипты взял от сюда: https://habr.com/ru/post/439728/ Но я их немного причесал под себя, сделав маленькие доработки. Итак, по будням, каждый вечер запускается вот такой скрипт:
(Который на сайте смотреть, всё-же, удобнее
http://typical-admin.ru/item/97-zimbra-backup) #!/bin/bash
# В этом скрипте Зимбра выгружает ящики на локальный диск, не сжимая. В обычный tar.
# Потом ящики сжимаются через pbzip2 и копируются в /mnt/mailbox_bkp/Arch-day.
# Выгружаются только ящики, заданные в ф

Устроившись на новую работу, я получил в своё владение работающий настроенный сервер Zimbra версии 8.8.15_GA_3847. Работает этот сервер на виртуальной машине, и бэкапирование делается двумя методами:

1. бэкапится сама виртуальная машина
2.1. бэкапятся почтовые ящики всех пользователей раз в неделю
2.2. бэкапятся почтовые ящики некоторых избранных пользователей по будням.

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

https://habr.com/ru/post/439728/

Но я их немного причесал под себя, сделав маленькие доработки.

Итак, по будням, каждый вечер запускается вот такой скрипт:
(Который на сайте смотреть, всё-же, удобнее
http://typical-admin.ru/item/97-zimbra-backup)

#!/bin/bash
# В этом скрипте Зимбра выгружает ящики на локальный диск, не сжимая. В обычный tar.
# Потом ящики сжимаются через pbzip2 и копируются в /mnt/mailbox_bkp/Arch-day.
# Выгружаются только ящики, заданные в файле /root/Backup_scripts/MBoxesList
PATH="/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin"
#Куда положить бэкап
Path="/mnt/mailbox_bkp/Backups"
#Куда положить архив бэкапа
ArchPath="/mnt/mailbox_bkp/Arch-day"
#Список ящиков
MBoxes="/root/Backup_scripts/MBoxesList"
#Текущая дата
CDate=$(date +%d-%m-%Y)
#Куда писать логи
log="/mnt/mailbox_bkp/BackUpLog.txt"
#Начало работы скрипта
echo -en
echo -en "day BackUp selected MailBoxes started `date '+%d.%m.%y'` in $(date +%T)\n" >> $log
#Очистка локального каталога от предыдущих выгрузок
echo -en "Clear catalog $Path\n" >> $log
rm -Rf $Path/*
#Проверка несуществования каталога для резервного копирования
if [ ! -d $Path ]; then
#Создание каталога хранения резервных копий
echo "Создание каталога хранения резервных копий..."
mkdir -p $Path
if [ $? -eq 0 ]; then
echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]"
echo
echo -en "BackUp dirctory was created in $(date +%T)\n" >> $log
else
echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]"
echo
echo -en "BackUp dirctory was NOT created in $(date +%T)\n" >> $log
fi
else
echo "Каталог хранения резервных копий существует, проверка существования каталога на сегодняшнее число..."
fi
#Првоерка несуществования каталога на сегодняшнюю дату
if [ ! -d $Path/$CDate ]; then
echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]"
echo
#Создание каталога хранения резервных копий на сегодняшнее число
echo "Создание каталога хранения резервных копий на сегодняшнее число..."
mkdir -p $Path/$CDate
if [ $? -eq 0 ]; then
echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]"
echo
echo -en "BackUp CDate dirctory was created in $(date +%T)\n" >> $log
else
echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]"
echo
echo -en "BackUp CDate dirctory was NOT created in $(date +%T)\n" >> $log
fi
else
echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]"
echo
echo "Каталог хранения резервных копий существует, запись списка ящиков в файл..."
fi
#создание резервных копий каждого ящика из списка
for MailBox in $( cat $MBoxes); do
echo "Создание резервной копии ящика $MailBox..."
/opt/zimbra/bin/zmmailbox -z -m $MailBox getRestUrl "//?fmt=tar" > $Path/$CDate/$MailBox
if [ $? -eq 0 ]; then
#Вывод результата создания резервной копии для каждого ящика
echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]"
echo
echo -en "Mail Box $MailBox BackUp created in $(date +%T)\n" >> $log
else
echo -n "$(tput hpa $(tput cols))$(tput cub 6)[FAIL]"
echo
echo -en "Mail Box $MailBox BackUp is NOT created! in $(date +%T)\n" >> $log
fi
done
#Создание архива и работа с архивами
#Проверка несуществования каталога для архивирвоания
if [ ! -d $ArchPath ]; then
#Создание каталога хранения архивов
echo "Создание каталога хранения архивов..."
mkdir -p $ArchPath
if [ $? -eq 0 ]; then
echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]"
echo
echo -en "Archive dirctory was created in $(date +%T)\n" >> $log
else
echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]"
echo
echo -en "Archive dirctory was NOT created in $(date +%T)\n" >> $log
fi
else
echo "Каталог хранения архивов существует, архививрование..."
fi
# создать tar используя сжатие pbzip2
tar -C $Path/ -cf $ArchPath/$CDate.tar --use-compress-prog=pbzip2 $CDate
if [ $? -eq 0 ]; then
echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]"
echo
echo -en "Archive created in $(date +%T)\n" >> $log
#Удаление старых архивов бэкапов (старше 2 недель)
echo "Удаление старых архивов резервных копий (старше 2 недель)..."
find $ArchPath -type f -mtime +14 -delete
if [ $? -eq 0 ]; then
echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]"
echo
echo -en "Old BackUps archives was deleted\n" >> $log
else
echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]"
echo
echo -en "Old BackUps archives is NOT deleted in $(date +%T)\n" >> $log
fi
else
echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]"
echo
echo -en "Archive is NOT created in $(date +%T)\n" >> $log
fi
echo "BackUp job finished in $(date +%T)"
#запись в лог-файл времени окончания резервного копирования
echo -en "BackUp job finished `date '+%d.%m.%y'` in $(date +%T)\n" >> $log
echo -en "_____________________________________________\n" >> $log

Скачать можно тут:

https://disk.yandex.ru/d/pNwWhgSYZr3A-w

В нём нужно лишь под себя поправить переменные:

#Куда положить бэкап
Path=

#Куда положить архив бэкапа
ArchPath=

#Список ящиков
MBoxes=

#Куда писать логи
log=

В файл со списком ящиков записаны нужные адреса в каждой отдельной строчке:

ivanov@mydomain.ru
petrov@mydomain.ru
utkin@mydomain.ru
popov@mydomain.ru
sidorov@mydomain.ru
kuznecov@mydomain.ru
и т.д.

По субботам запускается скрипт, бэкапящий все ящики заданного домена:

#!/bin/bash
# В этом скрипте Зимбра выгружает ящики на локальный диск, не сжимая. В обычный tar.
# Потом ящики сжимаются через pbzip2 и копируются в /mnt/mailbox_bkp/Arch-week.
PATH="/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin"
#Куда положить бэкап
Path="/mnt/mailbox_bkp/Backups"
#Куда положить архив бэкапа
ArchPath="/mnt/mailbox_bkp/Arch-week"
#Название домена Zimbra
ZDomain="mydomain.ru"
#Список ящиков
MBoxes="/mnt/mailbox_bkp/MBoxesList"
#Текущая дата
CDate=$(date +%d-%m-%Y)
#Куда писать логи
log="/mnt/mailbox_bkp/BackUpLog.txt"
#Начало работы скрипта
echo -en
echo -en "BackUp ALL MailBoxes started `date '+%d.%m.%y'` in $(date +%T)\n" >> $log
#Очистка локального каталога от предыдущих выгрузок
echo -en "Clear catalog $Path\n" >> $log
rm -Rf $Path/*
#Проверка несуществования каталога для резервного копирования
if [ ! -d $Path ]; then
#Создание каталога хранения резервных копий
echo "Создание каталога хранения резервных копий..."
mkdir -p $Path
if [ $? -eq 0 ]; then
echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]"
echo
echo -en "BackUp dirctory was created in $(date +%T)\n" >> $log
else
echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]"
echo
echo -en "BackUp dirctory was NOT created in $(date +%T)\n" >> $log
fi
else
echo "Каталог хранения резервных копий существует, проверка существования каталога на сегодняшнее число..."
fi
#Првоерка несуществования каталога на сегодняшнюю дату
if [ ! -d $Path/$CDate ]; then
echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]"
echo
#Создание каталога хранения резервных копий на сегодняшнее число
echo "Создание каталога хранения резервных копий на сегодняшнее число..."
mkdir -p $Path/$CDate
if [ $? -eq 0 ]; then
echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]"
echo
echo -en "BackUp CDate dirctory was created in $(date +%T)\n" >> $log
else
echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]"
echo
echo -en "BackUp CDate dirctory was NOT created in $(date +%T)\n" >> $log
fi
else
echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]"
echo
echo "Каталог хранения резервных копий существует, запись списка ящиков в файл..."
fi
#Запись списка ящиков в файл
/opt/zimbra/bin/zmprov -l gaa $ZDomain > $MBoxes
#Вывод результата записи списка
if [ $? -eq 0 ]; then
echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]"
echo
echo -en "Mail Boxes list created in $(date +%T)\n" >> $log
else
echo -n "$(tput hpa $(tput cols))$(tput cub 6)[FAIL]"
echo
echo -en "Mail Box list is NOT created! in $(date +%T)\n" >> $log
exit
fi
#создание резервных копий каждого ящика из списка
for MailBox in $( cat $MBoxes); do
echo "Создание резервной копии ящика $MailBox..."
/opt/zimbra/bin/zmmailbox -z -m $MailBox getRestUrl "//?fmt=tar" > $Path/$CDate/$MailBox
if [ $? -eq 0 ]; then
#Вывод результата создания резервной копии для каждого ящика
echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]"
echo
echo -en "Mail Box $MailBox BackUp created in $(date +%T)\n" >> $log
else
echo -n "$(tput hpa $(tput cols))$(tput cub 6)[FAIL]"
echo
echo -en "Mail Box $MailBox BackUp is NOT created! in $(date +%T)\n" >> $log
fi
done
#Очищаем файл со списком ящиков
echo "Очистка файла со споском ящиков..."
echo -n > $MBoxes
if [ $? -eq 0 ]; then
echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]"
echo
echo -en "File $MBoxes clear\n" >> $log
else
echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]"
echo
echo -en "File $MBoxes can NOT be cleared\n" >> $log
fi
#Создание архива и работа с архивами
#Проверка несуществования каталога для архивирвоания
if [ ! -d $ArchPath ]; then
#Создание каталога хранения архивов
echo "Создание каталога хранения архивов..."
mkdir -p $ArchPath
if [ $? -eq 0 ]; then
echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]"
echo
echo -en "Archive dirctory was created in $(date +%T)\n" >> $log
else
echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]"
echo
echo -en "Archive dirctory was NOT created in $(date +%T)\n" >> $log
fi
else
echo "Каталог хранения архивов существует, архививрование..."
fi
# создать tar используя сжатие pbzip2
tar -C $Path/ -cf $ArchPath/$CDate.tar --use-compress-prog=pbzip2 $CDate
if [ $? -eq 0 ]; then
echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]"
echo
echo -en "Archive created in $(date +%T)\n" >> $log
#Удаление старых архивов бэкапов (старше месяца)
echo "Удаление старых архивов резервных копий (старше месяца)..."
find $ArchPath -type f -mtime +32 -delete
if [ $? -eq 0 ]; then
echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]"
echo
echo -en "Old BackUps archives was deleted\n" >> $log
else
echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]"
echo
echo -en "Old BackUps archives is NOT deleted in $(date +%T)\n" >> $log
fi
else
echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]"
echo
echo -en "Archive is NOT created in $(date +%T)\n" >> $log
fi
echo "BackUp job finished in $(date +%T)"
#запись в лог-файл времени окончания резервного копирования
echo -en "BackUp job finished `date '+%d.%m.%y'` in $(date +%T)\n" >> $log
echo -en "_____________________________________________\n" >> $log

Скачать можно здесь же:

https://disk.yandex.ru/d/pNwWhgSYZr3A-w

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

#Куда положить бэкап
Path=

#Куда положить архив бэкапа
ArchPath=

#Название домена Zimbra
ZDomain=

#Список ящиков
MBoxes=

#Куда писать логи
log=

Для работы этих двух скриптов требуется пакет pbzip2.

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

Здесь лежат выгрузки почтовых ящиков:

-2

Также есть скрипт восстановления почты из ранее сделанной выгрузки. Вот он:

#!/bin/bash
#Где лежат бэкапы
Path="/mnt/mailbox_bkp/Backups"
#Название домена Zimbra
ZDomain="mydomain.ru"
#Список ящиков
MBoxes="/mnt/mailbox_bkp/MBoxesList"
#Куда писать логи
log="/mnt/mailbox_bkp/RestoreLog.txt"
read -p "Дата резервной копии, которую необходимо восстановить в формате 02-09-2001: " Date
if ! [ -d $Path/$Date ]; then
echo "Нет резервных копий на указанную дату."
echo -en "No BackUp file at $Date $(date +%T)\n" > $log
exit
fi
read -p "Введите имя почтового ящика (без указания домена), или ALL для восстановления всех почтовых ящиков на указанную дату: " A
if [[ "$A" = "ALL" || "$A" = "all" ]]; then
echo -en "Restore started in $(date +%T)\n" >> $log
#Запись списка ящиков в файл
ls "$Path/$Date" > $MBoxes
for MailBox in $( cat $MBoxes); do
#Проверка существования ящика
echo "Проверка существования ящика $MailBox"
Result=$(/opt/zimbra/bin/zmprov getMailboxInfo $MailBox)
if [ $? -eq 0 ]; then
echo -n "$(tput hpa $(tput cols))$(tput cub 6) [OK]"
echo
echo -en "Start restore job for $MailBox $(date +%T)\n" >> $log
echo "Ящик $MailBox существует. Восстановление..."
else
echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]"
echo
echo -en "Mail Box $MailBox does not exist, creating Mail Box $MailBox $(date +%T)\n" >> $log
echo "Ящик $MailBox не существует. Создание ящика $MailBox..."
#Проверка создания ящика
Result=$(/opt/zimbra/bin/zmprov ca $MailBox 12345678 displayName "$MailBox")
if [ $? -eq 0 ]; then
echo -n "$(tput hpa $(tput cols))$(tput cub 6) [OK]"
echo
echo -en "Mail Box $MailBox is created, starting restore $(date +%T)\n" >> $log
echo "Ящик $MailBox создан успешно. Восстановление..."
else
echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]"
echo
echo -en "Can NOT create Mail Box $MailBox ! $(date +%T)\n" >> $log
echo "Ящик $MailBox создать не удалось."
fi
fi
#Восстановление ящика
Result=$(/opt/zimbra/bin/zmmailbox -z -m $MailBox postRestURL "//?fmt=tar&resolve=replace" $Path/$Date/$MailBox)
if [ $? -eq 0 ]; then
echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]"
echo
echo -en "Ящик $MailBox восстановлен в $(date +%T)\n" >> $log
else
echo -n "$(tput hpa $(tput cols))$(tput cub 6)[FAIL]"
echo
echo -en "Ящик $MailBox НЕ восстановлен! $(date +%T)\n" >> $log
fi
done
else
#Проверка существования запрошенной резервной копии
MailBox="$A@$ZDomain"
if [ -a $Path/$Date/$MailBox ]; then
#Проверка существования ящика
echo "Проверка существования ящика $MailBox..."
Result=$(/opt/zimbra/bin/zmprov getMailboxInfo $MailBox)
if [ $? -eq 0 ]; then
echo -n "$(tput hpa $(tput cols))$(tput cub 6) [OK]"
echo
echo -en "Start restore job for $MailBox $(date +%T)\n" >> $log
echo "Ящик $MailBox существует. Восстановление..."
else
echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]"
echo
echo -en "Mail Box $MailBox does not exist $(date +%T)\n" >> $log
echo "Ящик $MailBox не существует."
read -p "Хотите создать почтовый ящик с указанным именем и восстановить в него резервную копию? [N]: " B
if [[ "$B" = "Y" || "$B" = "y" ]]; then
echo "Создание почтового ящика $MailBox..."
Result=$(/opt/zimbra/bin/zmprov ca $MailBox 12345678 displayName "$MailBox")
#Проверка создания ящика
if [ $? -eq 0 ]; then
echo -n "$(tput hpa $(tput cols))$(tput cub 6) [OK]"
echo
echo -en "Mail Box $MailBox is created, starting restore $(date +%T)\n" >> $log
echo "Ящик $MailBox создан успешно. Восстановление..."
else
echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]"
echo
echo -en "Can NOT create Mail Box $MailBox ! $(date +%T)\n" >> $log
echo "Ящик $MailBox создать не удалось. Завершение работы скрипта..."
exit
fi
else
#Ящик не будет создан, нечего восстанавливать. Выход
echo "Ящик не будет создан. Завершение работы скрипта"
exit
fi
fi
#Восстановление ящика
Result=$(/opt/zimbra/bin/zmmailbox -z -m $MailBox postRestURL "//?fmt=tar&resolve=replace" $Path/$Date/$MailBox)
if [ $? -eq 0 ]; then
echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]"
echo
echo -en "Ящик $MailBox восстановлен в $(date +%T)\n" >> $log
else
echo -n "$(tput hpa $(tput cols))$(tput cub 6)[FAIL]"
echo
echo -en "Ящик $MailBox НЕ восстановлен! $(date +%T)\n" >> $log
fi
else
#Запрошенной резервной копии не существует
echo "Запрошенной резервной копии не существует. Завершение работы скрипта"
echo -en "Required BackUp file is not exist\n" >> $log
exit
fi
fi
#Очищаем файл со списком ящиков
echo "Очистка файла со споском ящиков..."
echo -n > $MBoxes
if [ $? -eq 0 ]; then
echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]"
echo
else
echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]"
echo
fi
echo "BackUp job finished in $(date +%T) $(date +%T)"
#запись в лог-файл времени окончания резервного копирования
echo -en "Restore job complete in $(date +%T)\n" >> $log
echo -en "____________________________________\n" >> $log

Скачать снова здесь:

https://disk.yandex.ru/d/pNwWhgSYZr3A-w

Вкратце опишу, как им пользоваться. Для начала, надо в нём поправить переменные под себя:

#Где лежат бэкапы
Path=

#Название домена Zimbra
ZDomain=

#Список ящиков
MBoxes=

#Куда писать логи
log=

Допустим, хочу восстановить какой-нибудь старый ящик, который давно удалили, и о котором вспомнили уже спустя время. Сначала надо достать выгрузки почтовых ящиков из общего архива и положить их в каталог из переменной Path. У меня это каталог /mnt/mailbox_bkp/Backups. Общий архив лежит в каталоге /mnt/mailbox_bkp/Arch-day. Делаю это командой:

tar -xvf /mnt/mailbox_bkp/Arch-day/08-09-2022.tar --directory /mnt/mailbox_bkp/Backups

Получу вот такой результат:

-3

Если не получится распаковать сразу через tar, то можно попробовать разжать файл с помощью самой pbzip2, команда будет примерно такая:

pbzip2 -dk -p4 < /mnt/mailbox_bkp/Arch-day/08-09-2022.tar > /mnt/mailbox_bkp/backup.tar

Что разжать: /mnt/mailbox_bkp/Arch-day/08-09-2022.tar
Получаемый расжатый файл: /mnt/mailbox_bkp/backup.tar
-p4 – задействовать 4 потока процессора.

После этого уже распаковать разжатый файл через tar:

tar -xvf /mnt/mailbox_bkp/backup.tar --directory /mnt/mailbox_bkp/Backups

Далее уже можно запускать скрипт восстановления почтового ящика. Скрипт сначала попросит ввести дату резервной копии, которую надо восстановить. У меня это будет 08-09-2022. Если каталога с указанной датой не обнаружится, то скрипт завершит работу. А если каталог с такой датой присутствует, то скрипт спросит, какой ящик восстановить, либо попросит написать ALL для восстановления всех ящиков, которые найдёт в каталоге 08-09-2022.

Собственно, эти бэкап-скрипты можно переделать, чтобы общий архив делался обычным gzip или bzip2 и не заморачиваться с pbzip2, но тогда будет ощутимый проигрыш по времени, ведь, в отличие от gzip и bzip2, pbzip2 использует многопоточность.

Система работает на CentOS 7, но и на других Линуксах эти скрипты должны нормально работать.

Донаты принимаются на кошельки:

Yoomoney:
4100118091867315

Карта Т-Банк (бывший Тиньков):
2200 7017 2612 2077

Карта Альфа-Банк:
2200 1539 1357 2013

-4