Open Source Edition Backup Procedure: Difference between revisions

No edit summary
No edit summary
 
(18 intermediate revisions by 9 users not shown)
Line 1: Line 1:
{{Unsupported}}
{{BC|Community Sandbox}}
 
__FORCETOC__
If you wish to have a more automated backup feature, you should try the [Network Version of Zimbra.]
<div class="col-md-12 ibox-content">
= Open Source Edition Backup Procedure=
{{KB|{{Unsupported}}|{{ZCS 5.0}}|{{ZCS 4.5}}|}}
{{Archive}}
If you wish to have a more automated backup feature, you should try the Network Version of Zimbra.


==Backup Scripts==
==Backup Scripts==
Line 58: Line 62:
  # Create a mountpoint to mount the logical volume to
  # Create a mountpoint to mount the logical volume to
  say $GREEN"Creating a mountpoint for the LV..."
  say $GREEN"Creating a mountpoint for the LV..."
# WARNING: this is insecure!
  mkdir -p /tmp/ZimbraBackup
  mkdir -p /tmp/ZimbraBackup
   
   
  # Mount the logical volume to the mountpoint
  # Mount the logical volume to the mountpoint
  say $GREEN"Mounting the LV..."
  say $GREEN"Mounting the LV..."
# WARNING: remove nouuid option if the filesystem is not formatted as XFS !!! 
  mount -t $zimbra_vol_fs -o nouuid,ro /dev/$vol_group/ZimbraBackup /tmp/ZimbraBackup/
  mount -t $zimbra_vol_fs -o nouuid,ro /dev/$vol_group/ZimbraBackup /tmp/ZimbraBackup/
   
   
  # Start the Zimbra services
  # Start the Zimbra services
  say $CYAN"Starting the Zimbra services..."
  say $CYAN"Starting the Zimbra services..."
# WARNING: it's safer not to put this command in background
  /etc/init.d/zimbra start &
  /etc/init.d/zimbra start &
   
   
Line 87: Line 94:


===More elaborated script, using LVM and rsync===
===More elaborated script, using LVM and rsync===
More info at https://support.ginsys.be/websvn/listing.php?repname=zimbrackup <br />
More info at https://github.com/sergevanginderachter/sysadmintools/tree/master/zimbrackup <br />
Alternative link https://support.ginsys.be/svn/zimbrackup/trunk/ <br />
 
Send feedback to Serge van Ginderachter <svg@ginsys.be> <br />
===Yet another backup script, using LVM and duplicity===
 
The previous examples use ''tar'' and ''rsync'' respectively. Both have disadvantages:
 
* they don't support incremental backups
* you need to do additional scripting to encrypt the backup and purging of old backups
 
I modified the first script to use duplicity instead of plain ''tar''. This way you have the flexibility to use any protocol you like (scp, rsync, ftp) to upload the backup, you don't have to worry about old backups and you can save a lot of disk space!
 
Get the script: http://www.nervous.it/2007/01/zimbra-lvm-backup-with-duplicity-volume/
Get duplicity: http://duplicity.nongnu.org/


===The Perl way of doing it (without LVM)===
===The Perl way of doing it (without LVM)===
Line 571: Line 588:
The following script can be called from the command line or crontab, and relies only on rsync, tar, and a scriptable ftp client.  I used [http://www.ncftp.com ncftp] but you can use others and modify the syntax accordingly.  This script was written and tested in Ubuntu 6.06 LTS server.  I cannot confirm if it requires any modification to work in other distros but would appreciate feedback if necessary to make it more general.
The following script can be called from the command line or crontab, and relies only on rsync, tar, and a scriptable ftp client.  I used [http://www.ncftp.com ncftp] but you can use others and modify the syntax accordingly.  This script was written and tested in Ubuntu 6.06 LTS server.  I cannot confirm if it requires any modification to work in other distros but would appreciate feedback if necessary to make it more general.
<pre>
<pre>
#!/bin/bash
#!/bin/bash
   
   
# Zimbra Backup Script
# Zimbra Backup Script
# Requires ncftp to run
# Requires ncftp to run
# This script is intended to run from the crontab as root
# This script is intended to run from the crontab as root
# Date outputs and su vs sudo corrections by other contributors, thanks, sorry I don't have names to attribute!
# Date outputs and su vs sudo corrections by other contributors, thanks, sorry I don't have names to attribute!
# Free to use and free of any warranty!  Daniel W. Martin, 5 Dec 2008
# Free to use and free of any warranty!  Daniel W. Martin, 5 Dec 2008


   
   
# Outputs the time the backup started, for log/tracking purposes
# Outputs the time the backup started, for log/tracking purposes
echo Time backup started = $(date +%T)
echo Time backup started = $(date +%T)
before="$(date +%s)"
before="$(date +%s)"


# Live sync before stopping Zimbra to minimize sync time with the services down
# Live sync before stopping Zimbra to minimize sync time with the services down
# Comment out the following line if you want to try single cold-sync only
# Comment out the following line if you want to try single cold-sync only
rsync -avHK --delete /opt/zimbra/ /backup/zimbra
rsync -avHK --delete /opt/zimbra/ /backup/zimbra


# which is the same as: /opt/zimbra /backup  
# which is the same as: /opt/zimbra /backup  
# Including --delete option gets rid of files in the dest folder that don't exist at the src  
# Including --delete option gets rid of files in the dest folder that don't exist at the src  
# this prevents logfile/extraneous bloat from building up overtime.
# this prevents logfile/extraneous bloat from building up overtime.


# Now we need to shut down Zimbra to rsync any files that were/are locked
# Now we need to shut down Zimbra to rsync any files that were/are locked
# whilst backing up when the server was up and running.
# whilst backing up when the server was up and running.
before2="$(date +%s)"
before2="$(date +%s)"


# Stop Zimbra Services
# Stop Zimbra Services
su - zimbra -c"/opt/zimbra/bin/zmcontrol stop"
su - zimbra -c"/opt/zimbra/bin/zmcontrol stop"
sleep 15
sleep 15


# Kill any orphaned Zimbra processes
# Kill any orphaned Zimbra processes
kill -9 `ps -u zimbra -o "pid="`
ORPHANED=`ps -u zimbra -o "pid="` && kill -9 $ORPHANED


# Only enable the following command if you need all Zimbra user owned
# Only enable the following command if you need all Zimbra user owned
# processes to be killed before syncing
# processes to be killed before syncing
# ps auxww | awk '{print $1" "$2}' | grep zimbra | kill -9 `awk '{print $2}'`
# ps auxww | awk '{print $1" "$2}' | grep zimbra | kill -9 `awk '{print $2}'`
   
   
# Sync to backup directory
# Sync to backup directory
rsync -avHK --delete /opt/zimbra/ /backup/zimbra
rsync -avHK --delete /opt/zimbra/ /backup/zimbra


# Restart Zimbra Services
# Restart Zimbra Services
su - zimbra -c "/opt/zimbra/bin/zmcontrol start"
su - zimbra -c "/opt/zimbra/bin/zmcontrol start"


# Calculates and outputs amount of time the server was down for
# Calculates and outputs amount of time the server was down for
after="$(date +%s)"
after="$(date +%s)"
elapsed="$(expr $after - $before2)"
elapsed="$(expr $after - $before2)"
hours=$(($elapsed / 3600))
hours=$(($elapsed / 3600))
elapsed=$(($elapsed - $hours * 3600))
elapsed=$(($elapsed - $hours * 3600))
minutes=$(($elapsed / 60))
minutes=$(($elapsed / 60))
seconds=$(($elapsed - $minutes * 60))
seconds=$(($elapsed - $minutes * 60))
echo Server was down for: "$hours hours $minutes minutes $seconds seconds"
echo Server was down for: "$hours hours $minutes minutes $seconds seconds"


# Create a txt file in the backup directory that'll contains the current Zimbra
# Create a txt file in the backup directory that'll contains the current Zimbra
# server version. Handy for knowing what version of Zimbra a backup can be restored to.
# server version. Handy for knowing what version of Zimbra a backup can be restored to.
su - zimbra -c "zmcontrol -v > /backup/zimbra/conf/zimbra_version.txt"
su - zimbra -c "zmcontrol -v > /backup/zimbra/conf/zimbra_version.txt"
# or examine your /opt/zimbra/.install_history
# or examine your /opt/zimbra/.install_history


# Display Zimbra services status
# Display Zimbra services status
echo Displaying Zimbra services status...
echo Displaying Zimbra services status...
su - zimbra -c "/opt/zimbra/bin/zmcontrol status"
su - zimbra -c "/opt/zimbra/bin/zmcontrol status"
   
   
# Create archive of backed-up directory for offsite transfer
# Create archive of backed-up directory for offsite transfer
# cd /backup/zimbra
# cd /backup/zimbra
tar -zcvf /tmp/mail.backup.tgz -C /backup/zimbra .
umask 0177
tar -zcvf /tmp/mail.backup.tgz -C /backup/zimbra .
   
   
# Transfer file to backup server
# Transfer file to backup server
ncftpput -u <username> -p <password> <ftpserver> /<desired dest. directory> /tmp/mail.backup.tgz
ncftpput -u <username> -p <password> <ftpserver> /<desired dest. directory> /tmp/mail.backup.tgz


# Outputs the time the backup finished
rm /tmp/mail.backup.tgz
echo Time backup finished = $(date +%T)
 
# Outputs the time the backup finished
echo Time backup finished = $(date +%T)


# Calculates and outputs total time taken
# Calculates and outputs total time taken
after="$(date +%s)"
after="$(date +%s)"
elapsed="$(expr $after - $before)"
elapsed="$(expr $after - $before)"
hours=$(($elapsed / 3600))
hours=$(($elapsed / 3600))
elapsed=$(($elapsed - $hours * 3600))
elapsed=$(($elapsed - $hours * 3600))
minutes=$(($elapsed / 60))
minutes=$(($elapsed / 60))
seconds=$(($elapsed - $minutes * 60))
seconds=$(($elapsed - $minutes * 60))
echo Time taken: "$hours hours $minutes minutes $seconds seconds"
echo Time taken: "$hours hours $minutes minutes $seconds seconds"
</pre>
</pre>


Line 660: Line 680:
===A Simple Shell Script Method like above, but with rsync over ssh ===
===A Simple Shell Script Method like above, but with rsync over ssh ===


#!/bin/bash
#!/bin/bash
   
   
  # Zimbra Backup Script
  # Zimbra Backup Script
Line 667: Line 687:
  # Date outputs and su vs sudo corrections by other contributors, thanks, sorry I don't have names to attribute!
  # Date outputs and su vs sudo corrections by other contributors, thanks, sorry I don't have names to attribute!
  # Free to use and free of any warranty!  Daniel W. Martin, 5 Dec 2008
  # Free to use and free of any warranty!  Daniel W. Martin, 5 Dec 2008
# Adapted for rsync over ssh instead of ncftp by Ace Suares, 24 April 2009
## Adapted for rsync over ssh instead of ncftp by Ace Suares, 24 April 2009 (Ubuntu 6.06 LTS)
 
# the destination directory for local backups
# the destination directory for local backups
  DESTLOCAL=/backup/zimbra-backup
  DESTLOCAL=/backup/backup-zimbra
# the destination for remote backups
# the destination for remote backups
DESTREMOTE="yourserver:/backup/zimbra"
DESTREMOTE="yourserver:/backup/backup-zimbra"
   
   
  # Outputs the time the backup started, for log/tracking purposes
  # Outputs the time the backup started, for log/tracking purposes
  echo Time backup started = $(date +%T)
  echo Time backup started = $(date +%T)
  before="$(date +%s)"
  before="$(date +%s)"
# a backup dir on the local machine. This will fill up over time!
# a backup dir on the local machine. This will fill up over time!
BACKUPDIR=$DESTLOCAL/$(date +%F-%H-%M-%S)
BACKUPDIR=$DESTLOCAL/$(date +%F-%H-%M-%S)
 
  # Live sync before stopping Zimbra to minimize sync time with the services down
  # Live sync before stopping Zimbra to minimize sync time with the services down
  # Comment out the following line if you want to try single cold-sync only
  # Comment out the following line if you want to try single cold-sync only
rsync -avHK --delete --backup --backup-dir=$BACKUPDIR /opt/zimbra/ $DESTLOCAL/zimbra
rsync -avHK --delete --backup --backup-dir=$BACKUPDIR /opt/zimbra/ $DESTLOCAL/zimbra
 
  # which is the same as: /opt/zimbra /backup  
  # which is the same as: /opt/zimbra /backup  
  # Including --delete option gets rid of files in the dest folder that don't exist at the src  
  # Including --delete option gets rid of files in the dest folder that don't exist at the src  
  # this prevents logfile/extraneous bloat from building up overtime.
  # this prevents logfile/extraneous bloat from building up overtime.
# the backupdir will hold all files that changed or where deleted during the previous backup
# the backupdir will hold all files that changed or where deleted during the previous backup
 
  # Now we need to shut down Zimbra to rsync any files that were/are locked
  # Now we need to shut down Zimbra to rsync any files that were/are locked
  # whilst backing up when the server was up and running.
  # whilst backing up when the server was up and running.
  before2="$(date +%s)"
  before2="$(date +%s)"
 
  # Stop Zimbra Services
  # Stop Zimbra Services
/etc/init.d/zimbra stop
/etc/init.d/zimbra stop
#su - zimbra -c"/opt/zimbra/bin/zmcontrol stop"
#su - zimbra -c"/opt/zimbra/bin/zmcontrol stop"
#sleep 15
#sleep 15
  # Kill any orphaned Zimbra processes
  # Kill any orphaned Zimbra processes
#kill -9 `ps -u zimbra -o "pid="`
#kill -9 `ps -u zimbra -o "pid="`
pkill -9 -u zimbra
pkill -9 -u zimbra
 
  # Only enable the following command if you need all Zimbra user owned
  # Only enable the following command if you need all Zimbra user owned
  # processes to be killed before syncing
  # processes to be killed before syncing
Line 706: Line 726:
   
   
  # Sync to backup directory
  # Sync to backup directory
rsync -avHK --delete --backup-dir=$BACKUPDIR /opt/zimbra/ $DESTLOCAL
rsync -avHK --delete --backup --backup-dir=$BACKUPDIR /opt/zimbra/ $DESTLOCAL/zimbra
 
  # Restart Zimbra Services
  # Restart Zimbra Services
#su - zimbra -c "/opt/zimbra/bin/zmcontrol start"
#su - zimbra -c "/opt/zimbra/bin/zmcontrol start"
/etc/init.d/zimbra start
/etc/init.d/zimbra start
 
  # Calculates and outputs amount of time the server was down for
  # Calculates and outputs amount of time the server was down for
  after="$(date +%s)"
  after="$(date +%s)"
Line 719: Line 739:
  minutes=$(($elapsed / 60))
  minutes=$(($elapsed / 60))
  seconds=$(($elapsed - $minutes * 60))
  seconds=$(($elapsed - $minutes * 60))
echo SERVER WAS DOWN FOR: "$hours hours $minutes minutes $seconds seconds"
echo SERVER WAS DOWN FOR: "$hours hours $minutes minutes $seconds seconds"
 
  # Create a txt file in the backup directory that'll contains the current Zimbra
  # Create a txt file in the backup directory that'll contains the current Zimbra
  # server version. Handy for knowing what version of Zimbra a backup can be restored to.
  # server version. Handy for knowing what version of Zimbra a backup can be restored to.
su - zimbra -c "zmcontrol -v > $DESTLOCAL/zimbra/conf/zimbra_version.txt"
# su - zimbra -c "zmcontrol -v > $DESTLOCAL/zimbra/conf/zimbra_version.txt"
  # or examine your /opt/zimbra/.install_history
  # or examine your /opt/zimbra/.install_history
 
  # Display Zimbra services status
  # Display Zimbra services status
  echo Displaying Zimbra services status...
  echo Displaying Zimbra services status...
  su - zimbra -c "/opt/zimbra/bin/zmcontrol status"
  su - zimbra -c "/opt/zimbra/bin/zmcontrol status"
 
# /etc/init.d/zimbra status # seems not to work
# backup the backup dir (but not the backups of the backups) to remote
# backup the backup dir (but not the backups of the backups) to remote
rsync -essh -avHK --delete-during $DESTLOCAL/zimbra $DESTREMOTE
rsync -essh -avHK --delete-during $DESTLOCAL/zimbra $DESTREMOTE
   
   
  # Outputs the time the backup finished
  # Outputs the time the backup finished
  echo Time backup finished = $(date +%T)
  echo Time backup finished = $(date +%T)
 
  # Calculates and outputs total time taken
  # Calculates and outputs total time taken
  after="$(date +%s)"
  after="$(date +%s)"
Line 744: Line 764:
  seconds=$(($elapsed - $minutes * 60))
  seconds=$(($elapsed - $minutes * 60))
  echo Time taken: "$hours hours $minutes minutes $seconds seconds"
  echo Time taken: "$hours hours $minutes minutes $seconds seconds"
 
# end


===Backup Shell Script with Compressed & Encrypted Archives===
===Backup Shell Script with Compressed & Encrypted Archives===
Line 761: Line 782:




You can follow the development and find the latest info about usage and so on in the zimbra forum under the thread "Yet Another Backup Script Community Version"
You can follow the development and find the latest info about usage and so on in the zimbra forum under the thread "[[http://www.zimbra.com/forums/administrators/15275-yet-another-backup-script-community-version.html Yet Another Backup Script Community Version]]"
 
To download a current version of this script go to the forum thread there you will find a link to the file in the first post.
To download a current version of this script go to the forum thread there you will find a link to the file in the first post.
If you need any help you can contact me in the forum, I would be happy to help!
If you need any help you can contact me in the forum, I would be happy to help!
Line 789: Line 809:
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
# THE USE OF THIS DOCUMENT, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# THE USE OF THIS DOCUMENT, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# CONTRIBUTORS:
# heinzg of osoffice.de (original author)
# Quentin Hartman of Concentric Sky, qhartman@concentricsky.com (refactor and cleanup)
#
#
# What this script does:
# What this script does:
Line 798: Line 822:
# 6. Backup archive integrity checks and md5 checksums creation.
# 6. Backup archive integrity checks and md5 checksums creation.
# 7. Automated DR - Off-site copy of backup archives via ssh.
# 7. Automated DR - Off-site copy of backup archives via ssh.
# 8. Install and setup function for needed sofrware (Ubuntu Systems only)
# 8. Install and setup function for needed software (Ubuntu Systems only)
# 9. Weekly eMail report & eMail on error - including CC address.
# 9. Weekly eMail report & eMail on error - including CC address.
#
#
Line 809: Line 833:
#
#
# What is still to come or needs work on:
# What is still to come or needs work on:
# 1. Recover option
# 1. Recovery option
# 2. Better documentation
# 2. Better documentation
#
 
#------- CONFIG -------#
##------- CONFIG -------#
# Edit this part of the script to fit your needs.
# Edit this part of the script to fit your needs.
#


#--- Directories ---#
#--- Directories ---#
# Please add the trailing "/" to directories!
# Please add the trailing "/" to directories!
ZM_HOME=/opt/zimbra/
ZM_HOME=/opt/zimbra/ # where zimbra lives
SYNC_DIR=/tmp/fakebackup/
SYNC_DIR=/tmp/fakebackup/ # intermediate dir for hot/cold syncs. must have at least as much free space as ZM_HOME consumes
ARCHIVEDIR=/Backup/zimbra_dars/
ARCHIVEDIR=/Backup/zimbra_dars/ # where to store final backups
TOO_MEDIA_DIR=/Backup/burn/
TO_MEDIA_DIR=/Backup/burn/ # where to put fulls for archiving to media


#
#--- PROGRAM OPTIONS ---#  
#--- PROGRAM OPTIONS ---#  
RSYNC_OPTS="-aHK --delete --exclude=*.pid"
RSYNC_OPTS="-aHK --delete --exclude=*.pid" # leave these unless you are sure you need something else


#
#--- ARCHIVE NAMES ---#
#--- ARCHIVE NAMES ---#
BACKUPNAME="Zimbra_Backup"
BACKUPNAME="Zimbra_Backup" # what you want your backups called
BACKUPTYPE_F="FULL" # name prefix to sort between full and diff backups
FULL_PREFIX="FULL" # prefix used for full backups
BACKUPTYPE_D="DIFF"
DIFF_PREFIX="DIFF" # prefix used for differential backups
BACKUPDATE=`date +%d-%B-%Y`
BACKUPDATE=`date +%d-%B-%Y` # date format used in archive names
BACKUPWEEK=`date +%W` # Week prefix used for backup weekly rotation and naming


#
#--- ARCHIVE SIZE ---#
#--- ARCHIVE SIZE ---#
# storage media size
ARCHIVESIZE="4395M" # storage media size, for full-backup archiving
ARCHIVESIZE="4395M"
COMPRESS="9" # valid answers are 1 - 9 ( 9 = best )
COMPRESS="9" # valid answers are 1 - 9 ( 9 = best )


#--- Encryption Options ---#
CRYPT="yes" # valid answers are "yes" or "no"
CRYPT="yes" # valid answers are "yes" or "no"
PASSDIR=/etc/zmbac/
PASSDIR=/etc/`basename $0`/ # the directory the encryption hash is stored in.
PASSFILE="noread"
PASSFILE="noread" # the file containing the password hash


#
#--- Log Settings ---#
#--- EMAIL ADDRESS ---#
EMAIL="your@mailaddress.local" # the address to send logs to
EMAIL="heinzg@localhost"
EMAILCC="" # another address to send to
EMAILCC=""
LOG="/var/log/zim_backup.log" # log location
LOG="/var/log/zim_backup.log"


#--- SSH REMOTE DR COPY ---#
#--- SSH REMOTE DR COPY ---#
# This option will secure copy you archives to a remote server via 'scp'
# This option will secure copy your archives to a remote server via 'scp'
DRCP="yes" # valid answers are "yes" or "no"  
DRCP="no" # valid answers are "yes" or "no"  
SSHUSER="heinzg"
SSHUSER="you" # recommend creating a user on the remote machine just for transferring backups
SSHKEY="rsa"     # recommended answers are "rsa" or "dsa" but "rsa1" is also valid.
SSHKEY="rsa" # recommended answers are "rsa" or "dsa" but "rsa1" is also valid.
REMOTEHOST="172.16.184.1"
REMOTEHOST="remote.server.fqdn" # can use IP too
REMOTEDIR="/tmp/"
REMOTEDIR="/tmp/" # where you want your backups saved.


#--- USE HACKS !?! ---#
#--- Use Hacks? ---#
# Built in hacks to fix common problems
# Built in hacks to fix common problems
#Hack to start Stats, even run zmlogprocess if needed
#Hack to start Stats, even run zmlogprocess if needed
Line 867: Line 887:
# Best you don't change anything from here on,  
# Best you don't change anything from here on,  
# ONLY EDIT IF YOU KNOW WHAT YOU ARE DOING
# ONLY EDIT IF YOU KNOW WHAT YOU ARE DOING
#
#
# Check if Zimbra install dir is there
if [ ! -d $ZM_HOME ]
then
    echo "$ZM_HOME not found!"
    exit 1
fi
# Check the script is being run by root, or die.
ROOT_UID=0
if [ "$UID" -ne "$ROOT_UID" ]
then
  echo "Run script as "root"."
  echo
  exit 1
fi
# Create Log file
touch $LOG
# Script Timer
STARTTIME=(`date +%s`)
# Week prefix used for backup weekly rotation and naming
BACKUPWEEK=`date +%W`
# Finding out who is the zimbra proc user
ZM_USER=`ps -ef | grep "$ZM_HOME" | grep "java" | grep -v "zmmailboxdmgr" | awk '{print $1}' | head -n 1`
if [ -z $ZM_USER ]
then
    echo "Unable to determan the zimbra user"
    cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
    exit 1
    elif [ $ZM_USER = "root" ]
    then
echo "Zimbra user should never be root! I'll die now..."
# send email....
cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
exit 1
fi
# Location of Zimbra's PID files
STATPIDBASE="$ZM_HOME""zmstat/pid/"
case $1 in
    -V | --version)
    echo
    echo "Version 1.02"
    echo "first published Feb 08"
    echo
    echo "Change Log March 08:"
    echo "- Use the su command insted if sudo to stop and start services"
    echo "- Using shutdown insted of stop with zmcontrol"
    echo "- DATE_VERSION.txt now contains date and version and is created with full backups"
    echo "- Built in some more checks"
    echo "- eMail notification on error"
    echo "- Documentation - Added more comments"
    echo "- Dar archive is now built from current dir"
    echo "- Stats hack to make sure stats is starting again"
    echo "- 260 more lines of code... and who knows how many bugs"
    echo
    ;;
    -h | --help)
    echo
    echo "Configure the "CONFIG" part of the script to suit your needs."
    echo
    echo "USAGE:    -h or --help for help & usage."
    echo "          -f or --full for Full backup."
    echo "          -d or --diff for Diff backup."
    echo "          --INSTALL    for script install and setup."
    echo
    echo "Usage with cron, e.g."
    echo "0 3 * * 1    /bin/bash    /root/zmbac.sh -f > $LOG 2>&1"
    echo "0 3 * * 2-7  /bin/bash    /root/zmbac.sh -d >> $LOG 2>&1"
    echo
    ;;
    --INSTALL)
   
    # Check for configured Directories or Create them
   
    if [ ! -d $SYNC_DIR ]
    then
    echo
        echo "$SYNC_DIR not found!"
echo -n "Create $SYNC_DIR "y" or "n": "
read ANSWER
if [ $ANSWER = "y" ]
then
    mkdir -vp -m 600 $SYNC_DIR
else
    echo "Please check script Config, and try again"
    cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
    exit 1
fi
    fi
    if [ ! -d $ARCHIVEDIR ]
    then
    echo
echo "$ARCHIVEDIR not found!"
echo -n "Create $ARCHIVEDIR "y" or "n": "
read ANSWER
if [ $ANSWER = "y" ]
then
mkdir -vp -m 600 $ARCHIVEDIR
else
    echo "Please check script Config, and try again"
    cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
    exit 1
fi
    fi
    if [ ! -d $TOO_MEDIA_DIR ]
    then
    echo
    echo "directory $TOO_MEDIA_DIR not found!"
echo -n "Create $TOO_MEDIA_DIR "y" or "n": "
read ANSWER
if [ $ANSWER = "y" ]
then
    mkdir -vp -m 600 $TOO_MEDIA_DIR
else
    echo "Please check script Config, and try again"
    cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
    exit 1
fi
    fi
   
    # Check for needed software or try install it
   
    MAILX=`whereis mailx | awk '{print $2}'`
    if [ ! -e "$MAILX" ]
    then
    echo
echo "'mailx' is not installed!"
echo
echo "For a "Howto" install mailx without postfix please visit the link below"
echo "http://www.zimbra.com/forums/administrators/13528-sending-email-comand-line-logwatch-ubuntu-6-06-a.html#post70636"
echo
echo "Should I "try" install this for you?"
echo
echo "!! Only say yes if you are running Ubuntu!!"
echo
echo -n "install "y" or "n": "
read ANSWER
if [ $ANSWER = "y" ]
then
            echo
    echo "Downloading "mta-dummy" package to "/tmp""
    cd /tmp
    wget -v -S -c -t 40 --random-wait -T 60 http://ubuntu.lnix.net/misc/mta-dummy/mta-dummy_1.0_all.deb
    if [ "$?" -ne "0" ]
    then
            echo "Had some form of problem getting the mta-dummy package... ask for help in the forums"
echo
exit 1
    fi
        echo
        dpkg -i mta-dummy_1.0_all.deb
        if [ "$?" -ne "0" ]
        then
            echo "Had some form of problem getting installing the mta-dummy package... ask for help in the forums"
            echo
            exit 1
        fi
        echo
        echo
        apt-get -y install mailx
        if [ "$?" -ne "0" ]
        then
            echo "Had some form of problem installing 'mailx'... ask for help in the forums"
            echo
            exit 1
        fi
        echo
        echo "Writing config file "/etc/mail.rc""
echo "set sendmail=$ZM_HOME"postfix/sbin/sendmail"" >> /etc/mail.rc
        else
            echo "This script would like to send you a mail or two... so please install a dummy mta for your Distro"
    echo
    exit 1
fi
    fi
    UUENCODE=`whereis uuencode | awk '{print $2}'`
    if [ ! -e "$UUENCODE" ]
    then
    echo
echo "'uuencode' is not installed!"
echo
echo "Should I "try" install 'uuencode' for you?"
echo
echo "!! Only say yes if you are running Ubuntu!!"
echo -n "install "y" or "n": "
read ANSWER
if [ $ANSWER = "y" ]
then
    apt-get -y install sharutils
    if [ "$?" -ne "0" ]
    then
            echo "Had some form of problem installing "sharutils"... ask for help in the forums"
cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
exit 1
    fi
fi
    fi
    DAR_BIN=`whereis dar | awk '{print $2}'`
    if [ ! -e "$DAR_BIN" ]
    then
    echo
echo "'dar' is not installed!"
echo
echo "Should I "try" install 'dar' for you?"
echo
echo "!! Only say yes if you are running Ubuntu!!"
echo -n "install "y" or "n": "
read ANSWER
if [ $ANSWER = "y" ]
then
    apt-get -y install dar
    if [ "$?" -ne "0" ]
    then
            echo "Had some form of problem installing "dar"... ask for help in the forums"
cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
exit 1
    fi
fi
    fi
    SSH_BIN=`whereis ssh | awk '{print $2}'`
    if [ ! -e "$SSH_BIN" ]
    then
    echo
echo "Please install "ssh"!"
echo
echo "Should I "try" install a 'ssh client & server' for you?"
echo
echo "!! Only say yes if you are running Ubuntu!!"
echo -n "install "y" or "n": "
read ANSWER
if [ $ANSWER = "y" ]
then
    apt-get -y install openssh-server
    if [ "$?" -ne "0" ]
    then
            echo "Had some form of problem installing "openssh-server"... ask for help in the forums"
cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
echo
exit 1
    fi
fi
    fi
   
    if [ $CRYPT = "yes" ]
    then
    if [ ! -d "$PASSDIR" ]
    then
        echo "Create $PASSDIR"
        echo -n "install "y" or "n": "
        read ANSWER
    if [ $ANSWER = "y" ]
    then
        mkdir -vp -m 600 $PASSDIR
        echo "done"
        echo
    else   
    echo "Please check script Config, and try again"
    cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
    exit 1
    fi
fi
    fi
if [ ! -e "$PASSDIR""$PASSFILE" ]   
then
        echo "Create $PASSFILE"
        echo -n "install "y" or "n": "
        read ANSWER
        if [ $ANSWER = "y" ]
    then
        touch "$PASSDIR""$PASSFILE"
        chmod 600 "$PASSDIR""$PASSFILE"
        echo "'G'enerate or 'E'nter a secure passphrase"
        echo -n "please enter G or E: "
        read ANSWER
        if [ "$ANSWER" = "G" ]
        then
            openssl rand -base64 48 -out "$PASSDIR""$PASSFILE" 2>/dev/null
        else
            echo -n "Enter a secure passphrase: "
            read PASSPHRASE
            echo $PASSPHRASE > "$PASSDIR""$PASSFILE"
            echo "done"
            echo
        fi
    else   
        echo "Please check script Config, and try again"
        cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
        exit 1
    fi
fi
   
    echo
    if [ $DRCP = "yes" ]
    then
    echo
echo "For 'scp' to work, you have to have setup PKI authentication (passwork less login)"
echo "Should I try setup this for you?"
    echo "If you have a key an PKI authentication works answer 'n'"
echo -n "install "y" or "n": "
read ANSWER
if [ $ANSWER = "y" ]
then
    ssh-copy-id "$SSHUSER"@"$REMOTEHOST"
    if [ "$?" -ne "0" ]
    then
            echo "$?"
echo -n "Create ssh ID? "y" or "n": "
read ANSWER
    if [ $ANSWER = "y" ]
    then
        echo "Please except the 'defaults'and DO NOT ENTER A 'passphrase' !!"
        ssh-keygen -t "$SSHKEY"
        echo
        echo "copying your ID to $REMOTEHOST"
        echo "please enter your '$SSHUSER' user password on '$REMOTEHOST' at the prompt"
                    if [ "$SSHKEY" = "rsa" ]
                    then
                ssh-copy-id -i /root/.ssh/id_rsa "$SSHUSER"@"$REMOTEHOST"
                    elif [ "$SSHKEY" = "dsa" ]
                    then
                ssh-copy-id -i /root/.ssh/id_dsa "$SSHUSER"@"$REMOTEHOST"
                    elif [ "$SSHKEY" = "rsa1" ]
                    then
            ssh-copy-id -i /root/.ssh/identity "$SSHUSER"@"$REMOTEHOST"
                    fi
    fi
    fi
fi
    fi
    echo
    echo "Install cronjob to automate the nightly backups"
    echo -n "install "y" or "n": "
    read ANSWER
    if [ $ANSWER = "y" ]
    then
        crontab -l > $HOME/.crontab.save
        echo "Setting the time when to start the backup cycle"
        echo -n "At what hour? 0-23: "
        read HOUR
echo
echo -n "and what minute do you want the backup to start? 0-59: "
read MINUTE
echo
echo "path to script e.g. /root/scripts"
read SPATH
echo "" >> $HOME/.crontab.save
        echo "$MINUTE $HOUR * * 1    /bin/bash    $SPATH/zmbac.sh -f > $LOG 2>&1" >> $HOME/.crontab.save
        echo "$MINUTE $HOUR * * 2-7  /bin/bash    $SPATH/zmbac.sh -d >> $LOG 2>&1" >> $HOME/.crontab.save
        echo "" >> $HOME/.crontab.save
        crontab $HOME/.crontab.save
        rm $HOME/.crontab.save
        echo
        crontab -l
        echo
        echo "Done setting up crontab"
        echo
    fi
   
    ;;
    -f | --full)
    echo
    echo "      Full Backup started at: `date +%H:%M`"
    echo
    DAR_BIN=`whereis dar | awk '{print $2}'`
    if [ ! -e "$DAR_BIN" ]
    then
    echo "Please install "dar"!"
echo "Try running the script with --INSTALL"
exit 1
    fi
    MAILX=`whereis mailx | awk '{print $2}'`
    if [ ! -e "$MAILX" ]
    then
    echo "mailx is not installed!"
echo "Try running the script with --INSTALL"
exit 1
    fi
    RSYNC_BIN=`whereis rsync | awk '{print $2}'`
    if [ ! -f "$RSYNC_BIN" ]
    then
    echo $SYNC_BIN
echo "Please install "rsync"!"
echo "Try running the script with --INSTALL"
cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
exit 1
    fi
    SSH_BIN=`whereis ssh | awk '{print $2}'`
    if [ ! -e "$SSH_BIN" ]
    then
  echo "Please install "ssh"!"
echo "Try running the script with --INSTALL"
cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
exit 1
    fi
    MD5SUM_BIN=`whereis md5sum | awk '{print $2}'`
    if [ ! -e "$MD5SUM_BIN" ]
    then
  echo "Please install "md5sum"!"
echo "Try running the script with --INSTALL"
cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
exit 1
    fi
   
    if [ ! -d $ZM_HOME ]
    then
  echo "$ZM_HOME not found!"
cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
exit 1
    fi
    if [ ! -d $SYNC_DIR ]
    then
    echo "$SYNC_DIR not found!"
echo "Try running the script with --INSTALL"
cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
exit 1
    fi
    if [ ! -d $ARCHIVEDIR ]
    then
    echo "$ARCHIVEDIR not found!"
echo "Try running the script with --INSTALL"
cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
exit 1
    fi
    if [ ! -d $TOO_MEDIA_DIR ]
    then
    echo "directory $TOO_MEDIA_DIR not found!"
echo "Try running the script with --INSTALL"
cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
echo
exit 1
    fi
   
    # Look for old backups and put then in directory from where you write them to some form of
    # storage media
    LAST_FULL_DAR=`ls -A -1 $ARCHIVEDIR | grep $BACKUPNAME | cut -d _ -f1 | head -n1`
    if [ -z "$LAST_FULL_DAR" ]
    then
        echo "No old backups found"
    elif [ "$LAST_FULL_DAR" -lt "$BACKUPWEEK" ]
    then
        echo "Old backups found...old week= $LAST_FULL_DAR current week= $BACKUPWEEK"
        echo
        for i in `ls -A -1 "$ARCHIVEDIR""$LAST_FULL_DAR"_"$BACKUPNAME"*`
    #for i in `ls -A -1 "$ARCHIVEDIR""$LAST_FULL_DAR"_"$BACKUPNAME"*dar`
            do
                mv $i $TOO_MEDIA_DIR
                if [ "$?" -ne "0" ]
                then
                    echo "error during move!"
                    cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
                    exit 1
                else
                    echo "$i moved to $TOO_MEDIA_DIR"
                fi
            done
    fi
     
    # Checking for a backup file collisions. Creating Date and Marker file.
    CURRENTNAME1=`ls -A -1 "$ARCHIVEDIR""$BACKUPWEEK"_"$BACKUPNAME"_"$BACKUPDATE"_"$BACKUPTYPE_F"*dar 2> /dev/null | head -qn1`
    if [ -f "$CURRENTNAME1" ]
    then
        echo
        echo "Full Zimbra Backup failed!"
        echo "FOUND A BACKUP WITH SAME NAME IN $ARCHIVEDIR >> Please check why ????"
        echo "!! You should only run this script once a day with the current backup date settings !!"
cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
exit 1
    else
        su - "$ZM_USER" -c $ZM_HOME"bin/zmcontrol -v" > /dev/null
if [ -z "$?" ]
        then
            echo
            echo "zmcontrol has some problems! check config or call for help..."
            cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
            exit 1
else
    echo
    echo "Setting date & version Marker into "$ZM_HOME"DATE_VERSION.txt"
    echo
    echo "$BACKUPDATE" > "$ZM_HOME"DATE_VERSION.txt
    su - "$ZM_USER" -c $ZM_HOME"bin/zmcontrol -v" | grep ^R >> "$ZM_HOME"DATE_VERSION.txt
fi
# HotSync to backup directory
echo "Doing a hotsync of $ZM_HOME to $SYNC_DIR"
   
nice -19 $RSYNC_BIN $RSYNC_OPTS $ZM_HOME $SYNC_DIR
if [ "$?" -ne "0" ]
then
    echo
    echo "rsync had threw an hotsync error this is not that wild... continuing"
    #cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
else
        echo "sync went ok"
        echo
        fi
       
   
# Stopping Zimbra
echo "Stopping the Zimbra server"
echo
#Disable zimbra user's crontab, we don't want it starting any jobs while we backup
crontab -u $ZM_USER -l > "$ZM_HOME"crontab.org
if [ "$?" -ne "0" ]
then
    echo "could not backup "$ZM_USER"'s crontab..."
    echo "continuing with out changing users crontab!"
    cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
    exit 1
else
    touch "$ZM_HOME"crontab.blank
    crontab -u $ZM_USER "$ZM_HOME"crontab.blank
    rm "$ZM_HOME"crontab.blank
        echo "Deactivated "$ZM_USER"'s cronjobs"
    echo
    fi
#Starting 'service downtime' counter
DOWNTIMEA=(`date +%s`)
su - $ZM_USER -c $ZM_HOME"bin/zmcontrol stop"
if [ "$?" -eq "1" ]
then
    echo "zmcontrol shutdown had an error!"
    cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
    exit 1
else
            echo
    echo "Zimbra server has stopped "
fi
        echo
        # Some times I still have zimbra procs running, so I murder them! :-O
        sleep 5
        echo "kill any left over $ZM_USER procs"
        PROX=(`ps -u $ZM_USER | awk '{print $1}' | grep -v PID`)
        if [ "$PROX" ]
        then
            ps -u $ZM_USER | awk '{print $1}' | grep -v PID | xargs kill -s 15
            echo "Did a Mr. Bush on some left over procs..."
            echo 
        else
            echo "Nothing to kill"
            echo
        fi
        # ColdSyncing the zimbra server
        echo "Doing a fast cold sync..."
       
$RSYNC_BIN $RSYNC_OPTS $ZM_HOME $SYNC_DIR
        if [ "$?" -ne "0" ]
        then
            echo "rsync had threw an error!"
    echo "This should not happen at this stage... exiting!"
    cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
    exit 1
        else
            echo "sync went ok"
        fi
        echo
        # Starting the Zimbra server again
       
#Reinstate zimbra user's crontab
crontab -u $ZM_USER "$ZM_HOME"crontab.org
if [ "$?" -ne "0" ]
then
    echo "!!Could not reinstate "$ZM_USER"'s crontab!!"
    echo "Please do this manually!"
    cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
    exit 1
else
    echo "Reinstated "$ZM_USER"'s cronjobs"
    echo
        fi
su - "$ZM_USER" -c $ZM_HOME"bin/zmcontrol start"
        if [ "$?" -ne "0" ]
        then
            echo "There was an error starting Zimbra!"
            cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
            exit 1
        else
            echo
            echo "Zimbra has started"
        fi
# Service Timerc
DOWNTIMEB=(`date +%s`)
RUNTIME=$(expr $DOWNTIMEB \- $DOWNTIMEA)
hours=$(($RUNTIME / 3600))
seconds=$(($RUNTIME  % 3600))
minutes=$(($RUNTIME  / 60))
seconds=$(($RUNTIME  % 60))
echo
echo "Service down time was - Hr:$hours Min:$minutes Sec:$seconds"
        echo
       
        # Hack to start the stats component
        if [ $STATHACK = "yes" ]
    then
        echo "Running A hack... This one to check and start Stats subsystem"
#Checking if Stats is running
sleep 5
STAT_CK=(`su - "$ZM_USER" -c $ZM_HOME"bin/zmcontrol status" |grep -i stats | awk '{print $2}'`)
if [ "$STAT_CK" = "Stopped" ]
        then
                    echo "Stats is not running, thus booting Stats subsystem!"
                    echo
                    # Stopping Stats
    su - $ZM_USER -c $ZM_HOME"bin/zmstatctl stop"
                    if [ "$?" -ne "0" ]
                    then
                        echo "Stopping stats failed!"
                        cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
                        exit 1
                    else
        echo "Stats have been stopped"
                        echo
                    fi
    # Running Stats cronjob zmlogprocess manually
                    su - $ZM_USER -c $ZM_HOME"libexec/zmlogprocess" > /tmp/logprocess.out 2>&1
                    if [ "$?" -ne "0" ]
                    then
                        echo "Error running 'logprocess'"
                        echo
                        cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
                        exit 1
                    else
                        echo "Logprocess done..."
                        echo
                    fi
               
    # Running Stats cronjob zmqueuelog manually               
    su - $ZM_USER -c $ZM_HOME"libexec/zmqueuelog"
                    if [ "$?" -ne "0" ]
                    then
                        echo "Error running 'libexec/zmqueuelog'"
                        echo
                        cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
                        exit 1
                    else
                        echo "zmqueuelog done..."
                        echo
                    fi
   
    # Starting Stats
    sleep 2
    su - "$ZM_USER" -c $ZM_HOME"bin/zmstatctl start"
            if [ "$?" -ne "0" ]
    then
        echo "Starting stats failed!"
                        echo
        cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
        exit 1
    else
        echo "Stats started..."
    fi
            else
echo "Hack not needed Stats seems to be running fine..."
            fi
fi
         
        # Status Check to see that is running
STATUS=(`su - "$ZM_USER" -c "/opt/zimbra/bin/zmcontrol status" | grep -i Stopped`)
        if [ "$STATUS" ]
        then
            echo
            echo "Services that are not running"
            echo $STATUS
            cat $LOG | mail -c $EMAILCC -s "Zimbra Services Stopped on `hostname --fqdn`" $EMAIL
        else
            echo
            echo "All services are running"
            echo
        fi
        echo
        echo "Writing a full backup called:"
echo " $BACKUPWEEK"_"$BACKUPNAME"_"$BACKUPDATE"_"$BACKUPTYPE_F"
        echo "in: $ARCHIVEDIR with file sizes of max: $ARCHIVESIZE"
cd $SYNC_DIR
if [ $CRYPT = "yes" ]
then
    KEY=`cat "$PASSDIR""$PASSFILE"`
    echo "Archive is Encrypted"
    nice -19 $DAR_BIN -K bf:$KEY -s $ARCHIVESIZE -z$COMPRESS -Z "*.gz" -Z "*.zip"\
    -Z "*.bz2" -Z "*.tgz" -Z "*.zgz" -Z "*.jar" -Z "*.tiff" \
                    -Z "*.jpg" -Z "*.png" -Z "*.gif" -Z "*.jpeg" -R `pwd` \
                    -c "$ARCHIVEDIR""$BACKUPWEEK"_"$BACKUPNAME"_"$BACKUPDATE"_"$BACKUPTYPE_F" -Q
else       
    echo "Archive is NOT Encrypted!!!"
    nice -19 $DAR_BIN -s $ARCHIVESIZE -z$COMPRESS -Z "*.gz" -Z "*.zip"\
    -Z "*.bz2" -Z "*.tgz" -Z "*.zgz" -Z "*.jar" -Z "*.tiff" \
    -Z "*.jpg" -Z "*.png" -Z "*.gif" -Z "*.jpeg" -R `pwd` \
    -c "$ARCHIVEDIR""$BACKUPWEEK"_"$BACKUPNAME"_"$BACKUPDATE"_"$BACKUPTYPE_F" -Q
fi
        if [ "$?" -ne "0" ]
        then
            echo
            echo "Dar had a problem!"
            cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
            exit 1
        else
            echo "Archive Created successfully"
            echo
    # Create MD5 Checksums to verify archives after writing to media or network transfers
    cd $ARCHIVEDIR
    FILENAME=`ls -A "$BACKUPWEEK"_"$BACKUPNAME"_"$BACKUPDATE"_"$BACKUPTYPE_F"*`
    if [ -e $FILENAME ]
    then
    echo "Create MD5 Checksum for $FILENAME"
    $MD5SUM_BIN -b $FILENAME > "$FILENAME".md5
    if [ "$?" -ne "0" ]
    then
        echo
        echo "MD5 Checksum failed!"
        cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
        exit 1
    else
        echo
        echo "MD5 Checksum Created successfully"
                echo
    fi
    else
    echo "$FILENAME not found!"
echo "This should not happen"
echo
cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
exit 1
    fi
fi
# DRCP Section. To scp newly created archives to a remote system
if [ $DRCP = "yes" ]
then
    CPNAME=`ls -A "$BACKUPWEEK"_"$BACKUPNAME"_"$BACKUPDATE"_"$BACKUPTYPE_F"*`
    echo "copy archive to $REMOTEHOST" remote directory $REMOTEDIR
    scp -i /root/.ssh/id_rsa $CPNAME "$SSHUSER"@"$REMOTEHOST":"$REMOTEDIR"
if [ "$?" -ne "0" ]
then
            echo
    echo "Error copying archive and checksum to $REMOTEHOST"
                echo
    cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
    exit 1
        fi
fi
    fi
   
    # over view of all the files which where backed up
    echo
    echo "Create file listing from archive"
    if [ $CRYPT = "yes" ]
then
    KEY=`cat "$PASSDIR""$PASSFILE"`
    nice -19 $DAR_BIN -K bf:$KEY -l "$ARCHIVEDIR""$BACKUPWEEK"_"$BACKUPNAME"_"$BACKUPDATE"_"$BACKUPTYPE_F" -Q\
    > "$ARCHIVEDIR"Backuplist-"$BACKUPDATE".txt && gzip -9 "$ARCHIVEDIR"Backuplist-"$BACKUPDATE".txt
else       
    nice -19 $DAR_BIN -l "$ARCHIVEDIR""$BACKUPWEEK"_"$BACKUPNAME"_"$BACKUPDATE"_"$BACKUPTYPE_F" -Q\
    > "$ARCHIVEDIR"Backuplist-"$BACKUPDATE".txt && gzip -9 "$ARCHIVEDIR"Backuplist-"$BACKUPDATE".txt
fi
    # Script Timer
    STOPTIME=(`date +%s`)
    RUNTIME=$(expr $STOPTIME \- $STARTTIME)
    hours=$(($RUNTIME / 3600))
    seconds=$(($RUNTIME  % 3600))
    minutes=$(($RUNTIME  / 60))
    seconds=$(($RUNTIME  % 60))
    echo
    echo "::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
    echo "Full Zimbra Backup ended at: `date +%H:%M`"
    echo "Backup took Hr:$hours Min:$minutes Sec:$seconds to complete"
    echo ":::::::::::::::::Cheers Osoffice for the script:::::::::::::::::::::::"
    (cat $LOG; $UUENCODE "$ARCHIVEDIR"Backuplist-"$BACKUPDATE".txt.gz "$ARCHIVEDIR"Backuplist-"$BACKUPDATE".txt.gz) | mail -c $EMAILCC \
    -s "Zimbra Full Backup Log on `hostname --fqdn`" $EMAIL
    echo
    ;;
    -d | --diff)
    echo
    echo "      Diff Backup started at: `date +%H:%M`"
   
    DAR_BIN=`whereis dar | awk '{print $2}'`
    if [ ! -e "$DAR_BIN" ]
    then
    echo "Please install "dar"!"
echo "Try running the script with --INSTALL"
exit 1
    fi
    MAILX=`whereis mailx | awk '{print $2}'`
    if [ ! -e "$MAILX" ]
    then
    echo "mailx is not installed!"
echo "Try running the script with --INSTALL"
exit 1
    fi
    RSYNC_BIN=`whereis rsync | awk '{print $2}'`
    if [ ! -f "$RSYNC_BIN" ]
    then
    echo $SYNC_BIN
echo "Please install "rsync"!"
echo "Try running the script with --INSTALL"
cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
exit 1
    fi
    SSH_BIN=`whereis ssh | awk '{print $2}'`
    if [ ! -e "$SSH_BIN" ]
    then
  echo "Please install "ssh"!"
echo "Try running the script with --INSTALL"
cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
exit 1
    fi
    MD5SUM_BIN=`whereis md5sum | awk '{print $2}'`
    if [ ! -e "$MD5SUM_BIN" ]
    then
  echo "Please install "md5sum"!"
echo "Try running the script with --INSTALL"
cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
exit 1
    fi
   
    if [ ! -d $ZM_HOME ]
    then
  echo "$ZM_HOME not found!"
cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
exit 1
    fi
    if [ ! -d $SYNC_DIR ]
    then
    echo "$SYNC_DIR not found!"
echo "Try running the script with --INSTALL"
cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
exit 1
    fi
    if [ ! -d $ARCHIVEDIR ]
    then
    echo "$ARCHIVEDIR not found!"
echo "Try running the script with --INSTALL"
cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
exit 1
    fi
    if [ ! -d $TOO_MEDIA_DIR ]
    then
    echo "directory $TOO_MEDIA_DIR not found!"
echo "Try running the script with --INSTALL"
cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
echo
exit 1
    fi
       
    CURRENTNAME2=`ls -A -1 "$ARCHIVEDIR""$BACKUPWEEK"_"$BACKUPNAME"_"$BACKUPDATE"_"$BACKUPTYPE_D"*dar 2> /dev/null | head -qn1`
    CURRENTFULL=`ls -A -1 "$ARCHIVEDIR""$BACKUPWEEK"*FULL*dar 2>/dev/null | cut -d . -f1 `
    if [ -f "$CURRENTNAME2" ]
    then
        echo "Full Zimbra Backup failed! FOUND A BACKUP WITH SAME NAME"
        echo "Please check why! You should only run this script once a day with the current backup date settings!"
        cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
        exit 1
    elif [ $CURRENTFULL ]
    then
        echo
        # HotSync to backup directory
        echo "Doing a hotsync of $ZM_HOME to $SYNC_DIR"
nice -19 $RSYNC_BIN $RSYNC_OPTS $ZM_HOME $SYNC_DIR
        if [ "$?" -ne "0" ]
        then
            echo
    echo "rsync had threw an hotsync error this is not that wild... continuing"
            #cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
else
            echo
    echo "sync went ok"
    fi
         
    echo
    # Stopping Zimbra
    echo "Stopping the Zimbra server"
    echo
#Disable zimbra user's crontab, we don't want it starting any jobs while we backup
crontab -u $ZM_USER -l > "$ZM_HOME"crontab.org
if [ "$?" -ne "0" ]
then
    echo "could not backup "$ZM_USER"'s crontab..."
    echo "continuing with out changing users crontab!"
    cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
    exit 1
else
    touch "$ZM_HOME"crontab.blank
    crontab -u $ZM_USER "$ZM_HOME"crontab.blank
    rm "$ZM_HOME"crontab.blank
        echo "Deactivated "$ZM_USER"'s cronjobs"
    echo
    fi
#Starting 'service downtime' counter
DOWNTIMEA=(`date +%s`)
su - $ZM_USER -c $ZM_HOME"bin/zmcontrol stop"
if [ "$?" -eq "1" ]
then
    echo "zmcontrol shutdown had an error!"
    cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
    exit 1
else
            echo
    echo "Zimbra server has stopped "
fi
        echo
        # Some times I still have zimbra procs running, so I murder them! :-O
        sleep 5
        echo "kill any left over $ZM_USER procs"
        PROX=(`ps -u $ZM_USER | awk '{print $1}' | grep -v PID`)
        if [ "$PROX" ]
        then
            ps -u $ZM_USER | awk '{print $1}' | grep -v PID | xargs kill -s 15
            echo "Did a Mr. Bush on some left over procs..."
            echo 
        else
            echo "Nothing to kill"
            echo
        fi
        # ColdSyncing the zimbra server
        echo "Doing a fast cold sync..."
       
$RSYNC_BIN $RSYNC_OPTS $ZM_HOME $SYNC_DIR
        if [ "$?" -ne "0" ]
        then
            echo "rsync had threw an error!"
    echo "This should not happen at this stage... exiting!"
    cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
    exit 1
        else
            echo "sync went ok"
        fi
        echo
        # Starting the Zimbra server again
       
#Reinstate zimbra user's crontab
crontab -u $ZM_USER "$ZM_HOME"crontab.org
if [ "$?" -ne "0" ]
then
    echo "!!Could not reinstate "$ZM_USER"'s crontab!!"
    echo "Please do this manually!"
    cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
    exit 1
else
    echo "Reinstated "$ZM_USER"'s cronjobs"
    echo
        fi
su - "$ZM_USER" -c $ZM_HOME"bin/zmcontrol start"
        if [ "$?" -ne "0" ]
        then
            echo "There was an error starting Zimbra!"
            cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
            exit 1
        else
            echo
            echo "Zimbra has started"
        fi
# Service Timerc
DOWNTIMEB=(`date +%s`)
RUNTIME=$(expr $DOWNTIMEB \- $DOWNTIMEA)
hours=$(($RUNTIME / 3600))
seconds=$(($RUNTIME  % 3600))
minutes=$(($RUNTIME  / 60))
seconds=$(($RUNTIME  % 60))
echo
echo "Service down time was - Hr:$hours Min:$minutes Sec:$seconds"
        echo
       
        # Hack to start the stats component
        if [ $STATHACK = "yes" ]
    then
        echo "Running A hack... This one to check and start Stats subsystem"
#Checking if Stats is running
sleep 5
STAT_CK=(`su - "$ZM_USER" -c $ZM_HOME"bin/zmcontrol status" |grep -i stats | awk '{print $2}'`)
if [ "$STAT_CK" = "Stopped" ]
        then
                    echo "Stats is not running, thus booting Stats subsystem!"
                    echo
                    # Stopping Stats
    su - $ZM_USER -c $ZM_HOME"bin/zmstatctl stop"
                    if [ "$?" -ne "0" ]
                    then
                        echo "Stopping stats failed!"
                        cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
                        exit 1
                    else
        echo "Stats have been stopped"
                        echo
                    fi
    # Running Stats cronjob zmlogprocess manually
                    su - $ZM_USER -c $ZM_HOME"libexec/zmlogprocess" > /tmp/logprocess.out 2>&1
                    if [ "$?" -ne "0" ]
                    then
                        echo "Error running 'logprocess'"
                        echo
                        cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
                        exit 1
                    else
                        echo "Logprocess done..."
                        echo
                    fi
               
    # Running Stats cronjob zmqueuelog manually               
    su - $ZM_USER -c $ZM_HOME"libexec/zmqueuelog"
                    if [ "$?" -ne "0" ]
                    then
                        echo "Error running 'libexec/zmqueuelog'"
                        echo
                        cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
                        exit 1
                    else
                        echo "zmqueuelog done..."
                        echo
                    fi
   
    # Starting Stats
    sleep 2
    su - "$ZM_USER" -c $ZM_HOME"bin/zmstatctl start"
            if [ "$?" -ne "0" ]
    then
        echo "Starting stats failed!"
                        echo
        cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
        exit 1
    else
        echo "Stats started..."
    fi
            else
echo "Hack not needed Stats seems to be running fine..."
            fi
fi
         
        # Status Check to see that is running
STATUS=(`su - "$ZM_USER" -c "/opt/zimbra/bin/zmcontrol status" | grep -i Stopped`)
        if [ "$STATUS" ]
        then
            echo
            echo "Services that are not running"
            echo $STATUS
            cat $LOG | mail -c $EMAILCC -s "Zimbra Services Stopped on `hostname --fqdn`" $EMAIL
        else
            echo
            echo "All services are running"
            echo
    fi
    echo
   
    echo "Writing a diff backup called:"
    echo " $BACKUPWEEK"_"$BACKUPNAME"_"$BACKUPDATE"_"$BACKUPTYPE_D"
    echo "in: $ARCHIVEDIR with file sizes of max: $ARCHIVESIZE"
    cd $SYNC_DIR
if [ $CRYPT = "yes" ]
then
    KEY=`cat "$PASSDIR""$PASSFILE"`
    echo "Archive is Encrypted"
    nice -19 $DAR_BIN -J bf:$KEY -s $ARCHIVESIZE -z$COMPRESS -Z "*.gz" -Z "*.zip"\
    -Z "*.bz2" -Z "*.tgz" -Z "*.zgz" -Z "*.jar" -Z "*.tiff" \
                    -Z "*.jpg" -Z "*.png" -Z "*.gif" -Z "*.jpeg" -R `pwd` \
                    -c "$ARCHIVEDIR""$BACKUPWEEK"_"$BACKUPNAME"_"$BACKUPDATE"_"$BACKUPTYPE_D" -Q\
                    -A "$CURRENTFULL" -Q
else       
    echo "Archive is NOT Encrypted!!!"
    nice -19 $DAR_BIN -s $ARCHIVESIZE -z$COMPRESS -Z "*.gz" -Z "*.zip"\
    -Z "*.bz2" -Z "*.tgz" -Z "*.zgz" -Z "*.jar" -Z "*.tiff" \
    -Z "*.jpg" -Z "*.png" -Z "*.gif" -Z "*.jpeg" -R `pwd` \
    -c "$ARCHIVEDIR""$BACKUPWEEK"_"$BACKUPNAME"_"$BACKUPDATE"_"$BACKUPTYPE_D" -Q\
    -A "$CURRENTFULL" -Q
fi
        if [ "$?" -ne "0" ]
        then
            echo
            echo "Dar had a problem!"
            cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
            exit 1
        else
            echo "Archive Created successfully"
            echo
    # Create MD5 Checksums to verify archives after writing to media or network transfers
    cd $ARCHIVEDIR
    FILENAME=`ls -A "$BACKUPWEEK"_"$BACKUPNAME"_"$BACKUPDATE"_"$BACKUPTYPE_D"*`
    if [ -e $FILENAME ]
    then
    echo "Create MD5 Checksum for $FILENAME"
    $MD5SUM_BIN -b $FILENAME > "$FILENAME".md5
    if [ "$?" -ne "0" ]
    then
        echo
        echo "MD5 Checksum failed!"
        cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
        exit 1
    else
        echo
        echo "MD5 Checksum Created successfully"
                echo
    fi
    else
    echo "$FILENAME not found!"
echo "This should not happen"
echo
cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
exit 1
    fi
fi
# DRCP Section. To scp newly created archives to a remote system
if [ $DRCP = "yes" ]
then
    CPNAME=`ls -A "$BACKUPWEEK"_"$BACKUPNAME"_"$BACKUPDATE"_"$BACKUPTYPE_D"*`
    echo "copy archive to $REMOTEHOST" remote directory $REMOTEDIR
    scp -i /root/.ssh/id_rsa $CPNAME "$SSHUSER"@"$REMOTEHOST":"$REMOTEDIR"
if [ "$?" -ne "0" ]
then
            echo
    echo "Error copying archive and checksum to $REMOTEHOST"
                echo
    cat $LOG | mail -c $EMAILCC -s "Zimbra backup error on `hostname --fqdn`" $EMAIL
    exit 1
        fi
fi
    fi
   
    # over view of all the files which where backed up
    echo
    echo "Create file listing from archive"
    if [ $CRYPT = "yes" ]
then
    KEY=`cat "$PASSDIR""$PASSFILE"`
    nice -19 $DAR_BIN -K bf:$KEY -l "$ARCHIVEDIR""$BACKUPWEEK"_"$BACKUPNAME"_"$BACKUPDATE"_"$BACKUPTYPE_D" -Q\
    > "$ARCHIVEDIR"Backuplist-"$BACKUPDATE".txt && gzip -9 "$ARCHIVEDIR"Backuplist-"$BACKUPDATE".txt
else       
    nice -19 $DAR_BIN -l "$ARCHIVEDIR""$BACKUPWEEK"_"$BACKUPNAME"_"$BACKUPDATE"_"$BACKUPTYPE_D" -Q\
    > "$ARCHIVEDIR"Backuplist-"$BACKUPDATE".txt && gzip -9 "$ARCHIVEDIR"Backuplist-"$BACKUPDATE".txt
    fi
    # Script Timer
    STOPTIME=(`date +%s`)
    RUNTIME=$(expr $STOPTIME \- $STARTTIME)
    hours=$(($RUNTIME / 3600))
    seconds=$(($RUNTIME  % 3600))
    minutes=$(($RUNTIME  / 60))
    seconds=$(($RUNTIME  % 60))
    echo
    echo "::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
    echo "Diff Zimbra Backup ended at: `date +%H:%M`"
    echo "Backup took Hr:$hours Min:$minutes Sec:$seconds to complete"
    echo ":::::::::::::::Cheers Osoffice for the script:::::::::::::::::::::::::"
    echo
    ;;
    *)
    echo
    echo "use -h or --help for assistance"
    echo
    ;;


    esac
exit 0
</pre>
</pre>


Line 2,217: Line 1,038:
* The machine you are recovering to '''must''' have the same hostname as the original machine.
* The machine you are recovering to '''must''' have the same hostname as the original machine.


* Once you have your OS and all pre-requisites installed. Download and install Zimbra as normal.
* Once you have your OS and all pre-requisites installed. Download and install Zimbra as normal, using the same zimbra version as the backup. If it is a new server, you can install using install.sh -s to install just the packages to create the users and programs before recreating the old installation/


* Once Zimbra is installed, stop all Zimbra services and move/rename the /opt/zimbra folder:  
* Once Zimbra is installed, stop all Zimbra services and move/rename the /opt/zimbra folder:
  sudo -u zimbra /opt/zimbra/bin/zmcontrol shutdown
  sudo -u zimbra /opt/zimbra/bin/zmcontrol shutdown
  mv /opt/zimbra /tmp/zimbra-old
  mv /opt/zimbra /tmp/zimbra-old
Line 2,240: Line 1,061:
  zmcontrol startup
  zmcontrol startup


You should now be able to access Zimbra as normal.
You should now be able to access Zimbra as normal. If not, you may need to "upgrade" zimbra to set up the old configuration, for example if you have zimbra listening on a web port other than 80.
install.sh from the directory you extracted the zimbra install to. This will also restart services when completed, so you should be up and running


{{Article Footer|ZCS 4.0, 4.5.7 and 5.0.5|5/16/2006}}
{{Article Footer|ZCS 4.0, 4.5.7 and 5.0.5|5/16/2006}}


[[Category:Backup and Restore]]
[[Category:Backup and Restore]]
[[Category:Disaster Recovery]]
[[Category:ZCS 5.0]]
[[Category:ZCS 4.5]]

Latest revision as of 03:10, 11 July 2015

Open Source Edition Backup Procedure

   KB 1534        Last updated on 2015-07-11  




0.00
(0 votes)

If you wish to have a more automated backup feature, you should try the Network Version of Zimbra.

Backup Scripts

Backup Using LVM

If you have your Zimbra installation on its own logical volume, you can use this script:

#!/bin/bash
  
time=`date +%Y-%m-%d_%H-%M-%S`

# Modify the following variables according to your installation
#########################################

# backup_dir - directory to backup to
backup_dir=/path/to/backups/$time

# vol_group - the Volume Group that contains $zimbra_vol
vol_group=PUT_VOL_GROUPNAME_HERE

# zimbra_vol - the Logical Volume that contains /opt/zimbra
zimbra_vol=PUT_ZIMBRA_VOLNAME_HERE

# zimbra_vol_fs - the file system type (ext3, xfs, ...) in /opt/zimbra
zimbra_vol_fs=PUT_ZIMBRA_FILE_SYSTEM_TYPE_HERE

# lvcreate and lvremove commands path - 
lvcreate_cmd=`which lvcreate`
lvremove_cmd=`which lvremove`
  
# Do not change anything beyond this point
#########################################

# Test for an interactive shell
if [[ $- != *i* ]]
   then say() { echo -e $1; }
     # Colors, yo!
     GREEN="\e[1;32m"
     RED="\e[1;31m"
     CYAN="\e[1;36m"
     PURPLE="\e[1;35m"
   else say() { true; } # Do nothing
fi

# Output date
say $GREEN"Backup started at "$RED"`date`"$GREEN"."

# Stop the Zimbra services
say $CYAN"Stopping the Zimbra services..."
say $PURPLE"  This may take several minutes."
/etc/init.d/zimbra stop

# Create a logical volume called ZimbraBackup
say $GREEN"Creating a LV called ZimbraBackup:"$PURPLE
$lvcreate_cmd -L1000M -s -n ZimbraBackup /dev/$vol_group/$zimbra_vol

# Create a mountpoint to mount the logical volume to
say $GREEN"Creating a mountpoint for the LV..."
# WARNING: this is insecure!
mkdir -p /tmp/ZimbraBackup

# Mount the logical volume to the mountpoint
say $GREEN"Mounting the LV..."
# WARNING: remove nouuid option if the filesystem is not formatted as XFS !!!   
mount -t $zimbra_vol_fs -o nouuid,ro /dev/$vol_group/ZimbraBackup /tmp/ZimbraBackup/

# Start the Zimbra services
say $CYAN"Starting the Zimbra services..."
# WARNING: it's safer not to put this command in background
/etc/init.d/zimbra start &

# For testing only
#say $RED"Press Enter to continue...\e[0m"
#read input

# Create the current backup
say $GREEN"Creating the backup directory and backup..."
mkdir -p $backup_dir
tar zcvf $backup_dir/zimbra.backup.tar.gz /tmp/ZimbraBackup/zimbra/ 2&> /dev/null

# Unmount /tmp/ZimbraBackup and remove the logical volume
say $GREEN"Unmounting and removing the LV."$PURPLE
umount /tmp/ZimbraBackup/
$lvremove_cmd --force /dev/$vol_group/ZimbraBackup

# Done!
say $GREEN"Zimbra backed up to "$CYAN$backup_dir$GREEN"!"
say $GREEN"Backup ended at "$RED"`date`"$GREEN".\e[0m"

More elaborated script, using LVM and rsync

More info at https://github.com/sergevanginderachter/sysadmintools/tree/master/zimbrackup

Yet another backup script, using LVM and duplicity

The previous examples use tar and rsync respectively. Both have disadvantages:

  • they don't support incremental backups
  • you need to do additional scripting to encrypt the backup and purging of old backups

I modified the first script to use duplicity instead of plain tar. This way you have the flexibility to use any protocol you like (scp, rsync, ftp) to upload the backup, you don't have to worry about old backups and you can save a lot of disk space!

Get the script: http://www.nervous.it/2007/01/zimbra-lvm-backup-with-duplicity-volume/ Get duplicity: http://duplicity.nongnu.org/

The Perl way of doing it (without LVM)

ZCS Tools currently contains a Cold Backup script written in Perl. It also supports backup rotation. This script does not use LVM.

Currently: zimbraColdBackup-Ver0.02beta

#!/usr/bin/perl
use strict;
use warnings;
use POSIX;
use IO::Scalar; # for building up output on a string
use Proc::ProcessTable; # for killing processes
use File::Path; # for removing directories
use File::Rsync; # for syncing using rsync
use Mail::Mailer; # for sending email

#############################################################################
# Please make changes below to suit your system and requirements

# absolute path to'rsync' on your system
my $rsync       = '/usr/bin/rsync'; 

# absolute path to zimbra directory
my $zimbra      = '/opt/zimbra';

# absolute path to backup directory. ensure that it exists!
my $backup_dir  = '/backup';

# do you want to rotate backups?
my $rotate_bak  = 1; # 1 = yes, 0 = no

# if yes, after how many days?
# make sure that you don't specify '0'. Specifying zero will delete even
# the latest backup - that is, the backup taken today and you will end up
# with no data!
my $rotate_days = 7;

# do you want to send the backups to a remote location? (using rsync)
my $send_remote = 0; # 1 = yes, 0 = no

# if you would like to use Rsync to send to remote location:
# please enter the destination server below
# (before using the script make sure that you have password-less and
# passphrase-less SSH login setup using private / public cryptography
# this script will neither provide SSH password nor the passphrase
my $ssh_server  = 'host.domain.com'; # SSH server IP or hostname
my $remote_path = '/backups'; # path on remote server to send backup

# Finally:
# Do you want to have the results of backup emailed?
my $send_result = 1; # 1 = yes, 0 = no

# if yes, to whom whould it be emailed?
my $to_email    = 'smile@sis.net.in';

# CC email (optional: you can leave this empty)
my $cc_email    = '';

# BCC email (optional: you can leave this empty)
my $bcc_email   = '';

# Sender / From email (it will look like the email arrive from this person)
my $from_email  = 'root@localhost';

# That's it!
# Don't edit below this line unless you know what you're doing
#############################################################################

my $zimbra_user = 'zimbra';
my $prog_name = $0;

# properties of this program

# name of program
my $progname    = "zimbraColdBackup";
# version number
my $version     = "0.2Beta";
# revision number (independent of version number)
my $revision    = "30";
# license under which distributed
my $license     = qq(
#############################################################################
# Program Name      $progname                                        #
# Program Version   $version                                                 #
# Program Revision  $revision                                                      #
#                                                                           #
# This script can be used to backup Zimbra Collaboration Suite 4.0.0 GA     #
#                                                                           #
# Most recent version of this script can be downloaded from:                #
# http://sourceforge.net/projects/zcstools/                                 #
#                                                                           #
# Copyright (C) 2006 Chintan Zaveri                                         #
# E-mail: smile\@sis.net.in                                                  #
#                                                                           #
# This program is free software; you can redistribute it and/or modify      #
# it under the terms of the GNU General Public License version 2, as        #
# published by the Free Software Foundation.                                #
#                                                                           #
# This program is distributed in the hope that it will be useful,           #
# but WITHOUT ANY WARRANTY; without even the implied warranty of            #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             #
# GNU General Public License for more details.                              #
#                                                                           #
# You should have received a copy of the GNU General Public License along   #
# with this program; if not, write to the Free Software Foundation, Inc.,   #
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.               #
#############################################################################
);

# usage text
my $usage = qq(
Usage:
    zimbraColdBackup OPTION

    help|usage|?|--help|--usage
        All of these options, or providing no options will print this text
        about usage.

    overview|--overview
        What this script does.

    install|installation|--install|--installation
        These options will display a text on installation of this script.

    confirm|--confirm
        These options will run the backup procedure.

    version|--version
        These options will print the Name, Version and Revision Number for
        this script.

    license|licence|lisense|lisence|--license|--licence|--lisense|--lisence
        These options will print the License under which this program is
        distributed.
);

# overview text
my $overview = qq(
Overview:

This script can be used to take off-line backup of Zimbra Collaboration Suite.

The following is the series of actions undertaken by this script:

1. Stop Zimbra
2. Backup Zimbra in the specified local directory using Rsync
3. Start Zimbra

Optionally, if you specified, this script will also do the following:

1. Rotate the backups
2. Send the backup to another system using Rsync
3. Email the results of backup
);

# installation text
my $installation = qq(
Installation:

It is fairly easy to install this script. The installation requires you to do
the following:

1. Install all required Perl modules
2. Configure this script
3. Run it once - Test it!
4. Schedule it using crontab

1. Install all required Perl modules

The best way to do this is by running the script. Once you run the script, you
would receive an error message similar to the following:

Can't locate Mail/Mailer.pm in \@INC (\@INC contains:
/usr/lib/perl5/5.8.5/i386-linux-thread-multi /usr/lib/perl5/5.8.5
/usr/lib/perl5/site_perl/5.8.5/i386-linux-thread-multi
/usr/lib/perl5/site_perl/5.8.4/i386-linux-thread-multi
/usr/lib/perl5/site_perl/5.8.3/i386-linux-thread-multi
/usr/lib/perl5/site_perl/5.8.2/i386-linux-thread-multi
/usr/lib/perl5/site_perl/5.8.1/i386-linux-thread-multi
/usr/lib/perl5/site_perl/5.8.0/i386-linux-thread-multi
/usr/lib/perl5/site_perl/5.8.5 /usr/lib/perl5/site_perl/5.8.4
/usr/lib/perl5/site_perl/5.8.3 /usr/lib/perl5/site_perl/5.8.2
/usr/lib/perl5/site_perl/5.8.1 /usr/lib/perl5/site_perl/5.8.0
/usr/lib/perl5/site_perl
/usr/lib/perl5/vendor_perl/5.8.5/i386-linux-thread-multi
/usr/lib/perl5/vendor_perl/5.8.4/i386-linux-thread-multi
/usr/lib/perl5/vendor_perl/5.8.3/i386-linux-thread-multi
/usr/lib/perl5/vendor_perl/5.8.2/i386-linux-thread-multi
/usr/lib/perl5/vendor_perl/5.8.1/i386-linux-thread-multi
/usr/lib/perl5/vendor_perl/5.8.0/i386-linux-thread-multi
/usr/lib/perl5/vendor_perl/5.8.5 /usr/lib/perl5/vendor_perl/5.8.4
/usr/lib/perl5/vendor_perl/5.8.3 /usr/lib/perl5/vendor_perl/5.8.2
/usr/lib/perl5/vendor_perl/5.8.1 /usr/lib/perl5/vendor_perl/5.8.0
/usr/lib/perl5/vendor_perl .) at ./ZimbraColdBackup.pl line 9.
BEGIN failed--compilation aborted at ./zimbraColdBackup.pl line 9.

In the first line you can see that it is unable to locate Mail/Mailer.pm

To install this module, just type the following:

perl -MCPAN -e 'install Mail::Mailer'

This command will install the Mail::Mailer module.

Remember, the "/" must be converted to "::" when providing the command and
the ".pm" must be removed.

You may receive such errors for a few times. Just install the relevant
modules.

2. Configure the script

Once the modules are installed, you need to open this script in a text editor,
such as "vi" or "nano". Please enter correct values against the variables at
the top of the script. Once you open it in a text editor, it will become
self-explanatory.

3. Run it once - Test it!

Just say: "./zimbraColdBackup confirm" after you have configured it. It should
run and do as promised. If it doesn't just let me know, or ensure that it has
been properly configured.

4. Schedule it using crontab

Create a cron job using the command 'crontab -e' to run the script at fixed
intervals.
);

# parse the arguments

# if there are no arguments print usage and die
die $usage, @_ if ( $#ARGV + 1 < 1 );

# what was the argument? (ignore more than one arguments...)
my $option = $ARGV[0];

# select action
if (    ( $option =~ /^(--)?help$/ )     ||
        ( $option =~ /^(--)?usage$/ )    ||
        ( $option =~ /^\?$/) 
   ) {
        die $usage, @_;
}
elsif   ( $option =~ /^(--)?overview$/ ) {
        die $overview, @_;
}
elsif   ( $option =~ /^(--)?install(ation)?$/ ) {
        die $installation, @_;
}
elsif   ( $option =~ /^(--)?confirm$/ ) {
        1; # go ahead and run the script
}
elsif   ( $option =~ /^(--)?version$/) {
        die $progname, " Ver. ", $version, " Rev. ", $revision, "\n", @_;
}
elsif   ( $option =~ /^(--)?li[sc]en[sc]e$/ ) {
        die $license, @_;
}
else {
        die "Invalid option: Please try again", $usage, @_;
}

# going ahead and running the script :-)

# check inputs

if  ( ( $rsync eq "" ) || ( $rsync !~ /^\// ) ) {
    die "Please provide an absolute path to 'rsync'", "\n", @_;
}

if  (! ( -d $zimbra ) ) {
    die "Please provide an absolute path to 'zimbra' directory", "\n", @_;
}

if  (! ( -d $backup_dir ) ) {
    die "Please provide an absolute path to backup directory", "\n", @_;
}

if  ( $send_remote =~ /\D/ ) {
    die "Please enter either '1' or '0' in \$send_remote", "\n", @_;
}

if  ( $send_remote ) {
    # check ssh params
    if ( $ssh_server eq "" ) {
        die "Please enter valid SSH server to rsync to.", "\n", @_;
    }
}

if  ( $rotate_bak =~ /\D/ ) {
    die "Please enter either '1' or '0' in \$rotate_bak", "\n", @_;
}

if  ( $rotate_days =~ /\D/ ) {
    die "Please enter either '1' or '0' in \$rotate_days", "\n", @_;
}

if  ( $send_result =~ /\D/ ) {
    die "Please enter either '1' or '0' in \$send_result", "\n", @_;
}

if  ( $send_result ) {
    if  ( ! $to_email ) {
        die "Please enter valid email in \$to_email", "\n", @_;
    }
    if  ( ! $from_email ) {
        die "Please enter valid email in \$from_email", "\n", @_;
    }
}

# if you reach here, everything is valid, please proceed

my $result = '';
my $res_fh = IO::Scalar->new ( \$result );
# now whatever output we want to build up, we will print to $res_fh

print $res_fh "Date: ",
    POSIX::strftime ( '%m-%d-%Y, %A, %H:%M', localtime ( time ) ),
    " Hours\n";

# current day, date, month, time, ...
my $current_time = POSIX::strftime ( '%m-%d-%Y-%A-%H-%M', localtime ( time ) );
my $since_epoch = time ( ); # seconds since epoch

my $bak_dir = $backup_dir; # we want to use the backup dir path later
$backup_dir .= '/'.$current_time.'-'.$since_epoch;

# Stop Zimbra
my $zmstopstat = system ( "su - zimbra -c '$zimbra/bin/zmcontrol stop'" );
if ( $zmstopstat ) {
    print $res_fh "Stopping Zimbra: Some Problem Occurred. Please check.\n";
}
else {
    print $res_fh "Stopping Zimbra: Success\n";
}

# Kill all lingering Zimbra processes
my $zimbra_uid = getpwnam ( $zimbra_user );

my $process_table = Proc::ProcessTable->new;

# Gracefully kill lingering processes: kill -15, sleep, kill -9
foreach my $process ( @{$process_table->table} ) {
    if  ( ( $process->uid eq $zimbra_uid )          || 
        ( ( $process->cmndline =~ /$zimbra_user/ )  && 
        ( $process->cmndline !~ /$prog_name/ ) ) ) 
        {
            kill -15, $process->pid; # thanks, merlyn
            sleep 10; # not sure if there'll be buffering.
            kill -9, $process->pid;
    }
}

# Backup Zimbra using "rsync"
my $rsync_obj = File::Rsync->new ( {
    'rsync-path'    => $rsync,
    'archive'       => 1,
    'recursive'     => 1,
    'links'         => 1,
    'hard-links'    => 1,
    'keep-dirlinks' => 1,
    'perms'         => 1,
    'owner'         => 1,
    'group'         => 1,
    'devices'       => 1,
    'times'         => 1
} );

my $zmrsyncstat = $rsync_obj->exec ( { 
    src     =>  "$zimbra/", 
    dest    =>  "$backup_dir" 
} );

if ( $zmrsyncstat ) {
    print $res_fh "Rsync Zimbra: Successfully created $backup_dir\n";
}
else {
    print $res_fh "Rsync Zimbra: Some Problem Occurred. Please check.\n";
}

# Now that backup is done, start Zimbra
my $zmstartstat = system ( "su - zimbra -c '$zimbra/bin/zmcontrol start'" );
if ( $zmstartstat ) {
    print $res_fh "Starting Zimbra: Some Problem Occurred. Please check.\n";
}
else {
    print $res_fh "Starting Zimbra: Success\n";
}

print $res_fh "Zimbra was off-line for: ", time ( ) - $since_epoch, " seconds\n";

# Rotate backups
if ( $rotate_bak ) { # should we rotate backups?
    # get a list of all files from the backup directory
    opendir ( DIR, $bak_dir ) or die "can't opendir $bak_dir: $!";

    while ( defined ( my $filename = readdir ( DIR ) ) ) {
        # if $filename is . or .. do not remove it
            if ( $filename !~ /\./ ) { # if this isn't there, you're dead
            # if $filename is older than $rotation_days then delete it
            my @filename_parts = split ( "-", $filename ); # to get epoch sec
            # allowed age of backups
            my $allowed_age = $since_epoch - ( 60 * 60 * 24 * $rotate_days );
            # if the last part of $filename < allowed age
            if ( ( $filename_parts[6] < $allowed_age ) && ($filename ne "") ) {
                # delete it
                my $zmrmtreestat = rmtree ( "$bak_dir/$filename" );
                # print the status of removing
                if ( $zmrmtreestat ) {
                    print $res_fh "Rotating Backup: Removed $bak_dir/$filename\n";
                }
                else {
                    print $res_fh "Rotating Backup: Can't delete $filename\n";
                }
            }
        }
    }
    closedir ( DIR );
}

# Send to remote system
if ( $send_remote ) {
    # Backup Zimbra using "rsync"
    my $rem_rsync_obj = File::Rsync->new ( {
        'rsync-path'    => $rsync,
        'archive'       => 1,
        'recursive'     => 1,
        'links'         => 1,
        'hard-links'    => 1,
        'keep-dirlinks' => 1,
        'perms'         => 1,
        'owner'         => 1,
        'group'         => 1,
        'devices'       => 1,
        'times'         => 1
    } );
    my $destination =
$ssh_server.':'.$remote_path.'/'.$current_time.'-'.$since_epoch;
    my $zmremrsyncstat = $rem_rsync_obj->exec ( {
        src     =>  "$backup_dir/",
        dest    =>  "$destination"
    } );

    if ( $zmremrsyncstat ) {
        print $res_fh "Remote Rsync: Successfully created $destination\n";
    }
    else {
        print $res_fh "Remote Rsync: Some Problem Occurred. Please check.\n";
    }
}

print $res_fh "The backup took: ", time ( ) - $since_epoch, " seconds\n";

# Send email report
if ( $send_result ) {
    # send results by email
    my $mailer = Mail::Mailer->new ( "sendmail" );
    $mailer->open( {
        'From'      =>  $from_email,
        'To'        =>  $to_email,
        'Cc'        =>  $cc_email,
        'Bcc'       =>  $bcc_email,
        'Subject'   =>  'Result of zimbraColdBackup'
    } ) or die "Can't open: $!\n";
    print $mailer $result;
    $mailer->close();
}

# print results on std output
print $result;



NB: This script uses Mail::Mailer to send a notification using sendmail. You should make sure that sendmail is installed on your system and that it is not set to start at boot otherwise you'll have a conflict with the Zimbra MTA not starting.

A Simple Shell Script Method

The following script can be called from the command line or crontab, and relies only on rsync, tar, and a scriptable ftp client. I used ncftp but you can use others and modify the syntax accordingly. This script was written and tested in Ubuntu 6.06 LTS server. I cannot confirm if it requires any modification to work in other distros but would appreciate feedback if necessary to make it more general.

#!/bin/bash
 
# Zimbra Backup Script
# Requires ncftp to run
# This script is intended to run from the crontab as root
# Date outputs and su vs sudo corrections by other contributors, thanks, sorry I don't have names to attribute!
# Free to use and free of any warranty!  Daniel W. Martin, 5 Dec 2008

 
# Outputs the time the backup started, for log/tracking purposes
echo Time backup started = $(date +%T)
before="$(date +%s)"

# Live sync before stopping Zimbra to minimize sync time with the services down
# Comment out the following line if you want to try single cold-sync only
rsync -avHK --delete /opt/zimbra/ /backup/zimbra

# which is the same as: /opt/zimbra /backup 
# Including --delete option gets rid of files in the dest folder that don't exist at the src 
# this prevents logfile/extraneous bloat from building up overtime.

# Now we need to shut down Zimbra to rsync any files that were/are locked
# whilst backing up when the server was up and running.
before2="$(date +%s)"

# Stop Zimbra Services
su - zimbra -c"/opt/zimbra/bin/zmcontrol stop"
sleep 15

# Kill any orphaned Zimbra processes
ORPHANED=`ps -u zimbra -o "pid="` && kill -9 $ORPHANED

# Only enable the following command if you need all Zimbra user owned
# processes to be killed before syncing
# ps auxww | awk '{print $1" "$2}' | grep zimbra | kill -9 `awk '{print $2}'`
 
# Sync to backup directory
rsync -avHK --delete /opt/zimbra/ /backup/zimbra

# Restart Zimbra Services
su - zimbra -c "/opt/zimbra/bin/zmcontrol start"

# Calculates and outputs amount of time the server was down for
after="$(date +%s)"
elapsed="$(expr $after - $before2)"
hours=$(($elapsed / 3600))
elapsed=$(($elapsed - $hours * 3600))
minutes=$(($elapsed / 60))
seconds=$(($elapsed - $minutes * 60))
echo Server was down for: "$hours hours $minutes minutes $seconds seconds"

# Create a txt file in the backup directory that'll contains the current Zimbra
# server version. Handy for knowing what version of Zimbra a backup can be restored to.
su - zimbra -c "zmcontrol -v > /backup/zimbra/conf/zimbra_version.txt"
# or examine your /opt/zimbra/.install_history

# Display Zimbra services status
echo Displaying Zimbra services status...
su - zimbra -c "/opt/zimbra/bin/zmcontrol status"
 
# Create archive of backed-up directory for offsite transfer
# cd /backup/zimbra
umask 0177
tar -zcvf /tmp/mail.backup.tgz -C /backup/zimbra .
 
# Transfer file to backup server
ncftpput -u <username> -p <password> <ftpserver> /<desired dest. directory> /tmp/mail.backup.tgz

rm /tmp/mail.backup.tgz

# Outputs the time the backup finished
echo Time backup finished = $(date +%T)

# Calculates and outputs total time taken
after="$(date +%s)"
elapsed="$(expr $after - $before)"
hours=$(($elapsed / 3600))
elapsed=$(($elapsed - $hours * 3600))
minutes=$(($elapsed / 60))
seconds=$(($elapsed - $minutes * 60))
echo Time taken: "$hours hours $minutes minutes $seconds seconds"

One further note: I have observed some odd behavior in this and other scripts that, when run from the command line work flawlessly, but when run from crontab the script may get ahead of itself and, for example, try to ftp the file before tar is done creating it; resulting in a useless backup. Loading the script into crontab with the parameters to create a log file, for example

. /etc/zimbra.backup > /temp/zbackup.log 2>&1

seems to solve this problem (while creating the log, or showing the output on the screen, the script seems to follow the sequence more carefully), while giving you a line-by-line record of the backup procedure. In my installation with just over 3GB backed up, the logfile is 2.5 mb and is overwritten each night.

NB You may find that using su on your operating system has problems and some services don't start or stop correctly. If that's the case use 'sudo -u zimbra' in the following format for the commands:

sudo -u zimbra zmcontrol start

A Simple Shell Script Method like above, but with rsync over ssh

#!/bin/bash

# Zimbra Backup Script
# Requires that you have ssh-keys: https://help.ubuntu.com/community/SSHHowto#Public%20key%20authentication
# This script is intended to run from the crontab as root
# Date outputs and su vs sudo corrections by other contributors, thanks, sorry I don't have names to attribute!
# Free to use and free of any warranty!  Daniel W. Martin, 5 Dec 2008
## Adapted for rsync over ssh instead of ncftp by Ace Suares, 24 April 2009 (Ubuntu 6.06 LTS)

# the destination directory for local backups
DESTLOCAL=/backup/backup-zimbra
# the destination for remote backups
DESTREMOTE="yourserver:/backup/backup-zimbra"

# Outputs the time the backup started, for log/tracking purposes
echo Time backup started = $(date +%T)
before="$(date +%s)"
# a backup dir on the local machine. This will fill up over time!
BACKUPDIR=$DESTLOCAL/$(date +%F-%H-%M-%S)

# Live sync before stopping Zimbra to minimize sync time with the services down
# Comment out the following line if you want to try single cold-sync only
rsync -avHK --delete --backup --backup-dir=$BACKUPDIR /opt/zimbra/ $DESTLOCAL/zimbra

# which is the same as: /opt/zimbra /backup 
# Including --delete option gets rid of files in the dest folder that don't exist at the src 
# this prevents logfile/extraneous bloat from building up overtime.
# the backupdir will hold all files that changed or where deleted during the previous backup

# Now we need to shut down Zimbra to rsync any files that were/are locked
# whilst backing up when the server was up and running.
before2="$(date +%s)"

# Stop Zimbra Services
/etc/init.d/zimbra stop
#su - zimbra -c"/opt/zimbra/bin/zmcontrol stop"
#sleep 15
# Kill any orphaned Zimbra processes
#kill -9 `ps -u zimbra -o "pid="`
pkill -9 -u zimbra

# Only enable the following command if you need all Zimbra user owned
# processes to be killed before syncing
# ps auxww | awk '{print $1" "$2}' | grep zimbra | kill -9 `awk '{print $2}'`

# Sync to backup directory
rsync -avHK --delete --backup --backup-dir=$BACKUPDIR /opt/zimbra/ $DESTLOCAL/zimbra

# Restart Zimbra Services
#su - zimbra -c "/opt/zimbra/bin/zmcontrol start"
/etc/init.d/zimbra start

# Calculates and outputs amount of time the server was down for
after="$(date +%s)"
elapsed="$(expr $after - $before2)"
hours=$(($elapsed / 3600))
elapsed=$(($elapsed - $hours * 3600))
minutes=$(($elapsed / 60))
seconds=$(($elapsed - $minutes * 60))
echo SERVER WAS DOWN FOR: "$hours hours $minutes minutes $seconds seconds"

# Create a txt file in the backup directory that'll contains the current Zimbra
# server version. Handy for knowing what version of Zimbra a backup can be restored to.
# su - zimbra -c "zmcontrol -v > $DESTLOCAL/zimbra/conf/zimbra_version.txt"
# or examine your /opt/zimbra/.install_history

# Display Zimbra services status
echo Displaying Zimbra services status...
su - zimbra -c "/opt/zimbra/bin/zmcontrol status"
# /etc/init.d/zimbra status # seems not to work
# backup the backup dir (but not the backups of the backups) to remote
rsync -essh -avHK --delete-during $DESTLOCAL/zimbra $DESTREMOTE

# Outputs the time the backup finished
echo Time backup finished = $(date +%T)

# Calculates and outputs total time taken
after="$(date +%s)"
elapsed="$(expr $after - $before)"
hours=$(($elapsed / 3600))
elapsed=$(($elapsed - $hours * 3600))
minutes=$(($elapsed / 60))
seconds=$(($elapsed - $minutes * 60))
echo Time taken: "$hours hours $minutes minutes $seconds seconds"

# end

Backup Shell Script with Compressed & Encrypted Archives

This script has following features:

  • Easy to use!
  • Backups with or without strong encryption!
  • Compressed archives
  • Optional Off-site copying of archives after creation
  • MD5 checksums for integrity checks of archives
  • Weekly backup rotation - 1 Full & 6 Diff's per rotation
  • Email report on Full backup
  • Email notifications on errors
  • Backup file lists (attached to weekly full backup report)
  • Installer & Setup option for quick deployment (install needed software and setup env e.g. ssh pki auth and cronjobs)


You can follow the development and find the latest info about usage and so on in the zimbra forum under the thread "[Yet Another Backup Script Community Version]" To download a current version of this script go to the forum thread there you will find a link to the file in the first post. If you need any help you can contact me in the forum, I would be happy to help!

#!/bin/bash
## *** Info ***
# USAGE:    -h or --help for help & usage.
#           -f or --full for Full backup.
#           -d or --diff for Diff backup.
#           -V or --version for version info.
#           --INSTALL	 for script install and setup.
#
# This is a backup script for the FOSS version of Zimbra mail server.
# The script is free and open source and for use by anyone who can find a use for it.
#
# THIS SCRIPT IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
# HOLDERS AND/OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
# THE USE OF THIS DOCUMENT, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# CONTRIBUTORS:
# heinzg of osoffice.de (original author)
# Quentin Hartman of Concentric Sky, qhartman@concentricsky.com (refactor and cleanup)
#
# What this script does:
# 1. Makes daily off-line backups, at a service downtime of ~ < 2 min.
# 2. Weekly backup cycle - 1 full backup & 6 diffs.
# 3. Predefined archive sizes, for writing backups to CD or DVD media...
# 4. Backup archive compression.
# 5. Backup archive encryption.
# 6. Backup archive integrity checks and md5 checksums creation.
# 7. Automated DR - Off-site copy of backup archives via ssh.
# 8. Install and setup function for needed software (Ubuntu Systems only)
# 9. Weekly eMail report & eMail on error - including CC address.
#
# This script makes use of following tools:
# apt-get, cron, dar, dpkg, mailx, md5sum, rsync, ssh, uuencode, wget, zimbra mta.
#
# We have opted to use a pre-sync directory to save on "down time", but this 
# causes one to have huge additional space usage.
# But hard drives are cheep today!
#
# What is still to come or needs work on:
# 1. Recovery option
# 2. Better documentation

##------- CONFIG -------#
# Edit this part of the script to fit your needs.

#--- Directories ---#
# Please add the trailing "/" to directories!
ZM_HOME=/opt/zimbra/	# where zimbra lives
SYNC_DIR=/tmp/fakebackup/	# intermediate dir for hot/cold syncs. must have at least as much free space as ZM_HOME consumes
ARCHIVEDIR=/Backup/zimbra_dars/	# where to store final backups
TO_MEDIA_DIR=/Backup/burn/	# where to put fulls for archiving to media

#--- PROGRAM OPTIONS ---# 
RSYNC_OPTS="-aHK --delete --exclude=*.pid" # leave these unless you are sure you need something else

#--- ARCHIVE NAMES ---#
BACKUPNAME="Zimbra_Backup"	# what you want your backups called
FULL_PREFIX="FULL"	# prefix used for full backups
DIFF_PREFIX="DIFF"	# prefix used for differential backups
BACKUPDATE=`date +%d-%B-%Y`	# date format used in archive names
BACKUPWEEK=`date +%W`	# Week prefix used for backup weekly rotation and naming

#--- ARCHIVE SIZE ---#
ARCHIVESIZE="4395M"	# storage media size, for full-backup archiving
COMPRESS="9"		# valid answers are 1 - 9 ( 9 = best )

#--- Encryption Options ---#
CRYPT="yes"		# valid answers are "yes" or "no"
PASSDIR=/etc/`basename $0`/ # the directory the encryption hash is stored in. 
PASSFILE="noread"	# the file containing the password hash

#--- Log Settings ---#
EMAIL="your@mailaddress.local"	# the address to send logs to
EMAILCC=""				# another address to send to
LOG="/var/log/zim_backup.log"	# log location

#--- SSH REMOTE DR COPY ---#
# This option will secure copy your archives to a remote server via 'scp'
DRCP="no"		# valid answers are "yes" or "no" 
SSHUSER="you"	# recommend creating a user on the remote machine just for transferring backups	
SSHKEY="rsa"	# recommended answers are "rsa" or "dsa" but "rsa1" is also valid.
REMOTEHOST="remote.server.fqdn"	# can use IP too
REMOTEDIR="/tmp/"	# where you want your backups saved.

#--- Use Hacks? ---#
# Built in hacks to fix common problems
#Hack to start Stats, even run zmlogprocess if needed
STATHACK="yes" 		# valid answers are "yes" or "no"


## ~~~~~!!!! SCRIPT RUNTIME !!!!!~~~~~ ##
# Best you don't change anything from here on, 
# ONLY EDIT IF YOU KNOW WHAT YOU ARE DOING

Snapshots

While the above three methods can be used on a rotating fashion, their mainly full copies; as anyone with a 20TB store knows, backups take up space.

Thus, this section is devoted to reducing storage needed through incrementalish snapshots.

-Labeled 'ish' because this is nothing like the NE method of hot/live backups using redologs to restore to any given second.

-In short, so we don't confuse it with NE, please don't say "my incrementals aren't working" in the forums without first mentioning that you're using a FOSS method.

(Hence this is labled 'snapshots' to cut down on some confusion.)

Utilities to help you make rotating snapshots:

rsnapshot

rdiff-backup

An rsync script

Another script being worked out: http://www.zimbra.com/forums/showthread.php?threadid=15275

Another: http://www.zimbra.com/forums/showthread.php?threadid=15963

Emergency Repairs

Preparing to Back Up

Before we begin, make sure that you are logged in as a user that can perform the tasks outlined here.

It is always good practice to backup your copy of Zimbra in the event of unforeseen circumstances.

To prevent changes to any Zimbra databases during the backup processes you may wish to use:

>su zimbra
>zmcontrol stop

to terminate Zimbra.

If you get some kind of error, you may want to make sure that Zimbra has completly stopped by running:

>ps auxww | grep zimbra

and kill any left over processes such as the log.

Alternatively as root you could run the following command to kill all Zimbra user owned processes instantly (use wisely):

>ps auxww | awk '{print $1" "$2}' | grep zimbra | kill -9 `awk '{print $2}'`

Backing Up

Make sure that the copy location has enough space to support your backup copy (i.e. the /tmp folder probably isn't the best location).

Since all of the components Zimbra needs are stored in the Zimbra folder itself, you can simply copy the folder to a safe location.

It may be possible to create a cron job to do these tasks automatically.

Copy Command: cp -Rp /opt/zimbra [location path]

Depending on your hardware and the amount of data contained in your Zimbra installation, this process can take a while.

Note: It is a very good idea to tag your installation with the version/build of zimbra that will be backed up (ie 3.0.0_GA_156) and the date of backup. You'll need this later.

Restoring

Before restoring, you should make sure that all of the processes accociated with the damaged/failed Zimbra installation are terminated. Failure to terminate all of the processes could have dire consquences. See "Preparing to Backup" for additional info.

====Rename your "broken" Zimbra installation.'

You may be able to scavenge data, if needed. If you simply do not want the old data, you can skip this part.

>mv /opt/zimbra [new location i.e. /tmp/zimbra-old]

You may want to move it completly out of the /opt folder just to be safe.

Copy your backup Zimbra installation to the /opt folder and name it "zimbra".

>cp -rp [location of backup] /opt
>mv /opt/[backup name] /opt/zimbra

Restore to Existing/Backup Zimbra Server

In the event of a failure, you can either restore your /opt/zimbra folder to a server that is not currently running Zimbra and download a dummy copy of Zimbra and run an upgrade in order to clean everything up and make it run correctly again (see next section), or you may restore the backup to an existing Zimbra server. This will only work if the existing server is running the EXACT SAME VERSION of Zimbra as the backup you want to restore. Also, this has been tested and seems to work well with CE 4.5.8, but did not work with 4.5.7. This may be, for example, a backup email server that you want to always keep current with last night's backup, so it can replace the production server on short notice in the event of a disaster.

Simply set up your backup server identical to your production server (preferably the same OS, but necessarily the exact same version of Zimbra). Any modifications you made or packages you added for your production server with regards to extra anti-spam protection, etc., should also be added to this server. Shut down Zimbra on the backup server. Copy /opt/zimbra from your backup to the backup server.

chown -R zimbra:zimbra /opt/zimbra
/opt/zimbra/libexec/zmfixperms

Start Zimbra. Everything should work. The advantage to this method is that you can retain all your customizations (anti-spam modifications, for example) that would otherwise have been lost in the "upgrade" method. Also, this allows you to use a script to keep a backup server current without having to reinstall Zimbra after each time the backup server is made current, or before putting the backup server into production in the event of a failure.

Downloading a Dummy Copy of Zimbra

Now, we need to know what build/version of zimbra you were running. If you followed the backup instructions above, then the backup folder should be tagged with the version/build you have backed up.

You need to download the full install of the Zimbra version you were running. You may find all Zimbra releases at: Sourceforge.

If you don't know your version number, you can find it by:

Method 1 - view install_history file.

cat /opt/zimbra/.install_history

Method 2 - dont think this will work unless you did a bunch of chroots.

zmcontrol -v

Both of the above listed methods were from this forum post

Installing the Dummy Copy of Zimbra

Once you have downloaded the tar file, you will need to uncompress it by:

>tar -xvzf [name of file].tgz

This will create a folder in the directory named "zcs", cd to it and run the install script:

>cd zcs
>./install.sh

WARNING: Do not run the script with the -u option. You will remove all of your backup data & you must run the script as root, NOT ZIMBRA.

The script will remove the existing packages, and install them again. The script will attempt to stop Zimbra Services and "UPGRADE FAILED - exiting". This is okay, simply rerun the script, and it will install normally.

If you experence error 389, -1, connection refused errors, please search the Forums. These errors are covered extensivly.

Resetting Permissions

If you are up and running now, you may have one more hurdle to overcome: permissions.

You may need to reset the permissions on the message store by running the following:

>/opt/zimbra/libexec/zmfixperms

This is potentially a dangerous suggestion, but if you have trouble getting tomcat to start even after you run zmfixperms, try running (worked for ZCS 4.5.7 CE)

chown -R zimbra:zimbra /opt/zimbra

Of course, you must run

/opt/zimbra/libexec/zmfixperms

again after that. It appears that zmfixperms is supposed to chown zimbra:zimbra on something, but it misses it. This way, you chown EVERYTHING zimbra:zimbra, and zmfixperms puts back things that need to be owned as root, postfix, etc.

Disaster Recovery

In the unfortunate event of losing your complete server or installation, the following will get you up and running.

This has been tested successfully on v5.0.5

  • The machine you are recovering to must have the same hostname as the original machine.
  • Once you have your OS and all pre-requisites installed. Download and install Zimbra as normal, using the same zimbra version as the backup. If it is a new server, you can install using install.sh -s to install just the packages to create the users and programs before recreating the old installation/
  • Once Zimbra is installed, stop all Zimbra services and move/rename the /opt/zimbra folder:
sudo -u zimbra /opt/zimbra/bin/zmcontrol shutdown
mv /opt/zimbra /tmp/zimbra-old
  • Uncompress the most recent backup file to the /opt/zimbra folder
mkdir /opt/zimbra
tar zxvf [backup file] -C /opt/zimbra

or if you prefer...

tar zxvf [backup file] -C /tmp/zimbra-backup
cp -Rp /tmp/zimbra-backup /opt/zimbra
  • Fix the Zimbra permissions
chown -R zimbra:zimbra /opt/zimbra
/opt/zimbra/libexec/zmfixperms
  • Restart all Zimbra services
sudo -u zimbra /opt/zimbra/bin/zmcontrol startup
zmcontrol startup

You should now be able to access Zimbra as normal. If not, you may need to "upgrade" zimbra to set up the old configuration, for example if you have zimbra listening on a web port other than 80. install.sh from the directory you extracted the zimbra install to. This will also restart services when completed, so you should be up and running

Verified Against: ZCS 4.0, 4.5.7 and 5.0.5 Date Created: 5/16/2006
Article ID: https://wiki.zimbra.com/index.php?title=Open_Source_Edition_Backup_Procedure Date Modified: 2015-07-11



Try Zimbra

Try Zimbra Collaboration with a 60-day free trial.
Get it now »

Want to get involved?

You can contribute in the Community, Wiki, Code, or development of Zimlets.
Find out more. »

Looking for a Video?

Visit our YouTube channel to get the latest webinars, technology news, product overviews, and so much more.
Go to the YouTube channel »

Jump to: navigation, search