Open Source Edition Backup Procedure

Revision as of 09:23, 31 March 2008 by Heinzg (talk | contribs)

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

# 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
/usr/sbin/lvcreate -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..."
mkdir -p /tmp/ZimbraBackup

# Mount the logical volume to the mountpoint
say $GREEN"Mounting the LV..."
mount -t $zimbra_vol_fs -o nouuid,ro /dev/$vol_group/ZimbraBackup /tmp/ZimbraBackup/

# Start the Zimbra services
say $CYAN"Starting the Zimbra services..."
/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/
/usr/sbin/lvremove --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

Download at https://support.ginsys.be/svn/zimbrackup/
Send feedback to Serge van Ginderachter <svg@ginsys.be>

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
 # Free to use and free of any warranty!  Daniel W. Martin, 9 Sept 2007
 
 # 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.

 # Stop Zimbra Services
 sudo -u zimbra /opt/zimbra/bin/zmcontrol stop
 sleep 20
 
 # Sync to backup directory
 rsync -avHK --delete /opt/zimbra/ /backup/zimbra

 # Restart Zimbra Services
 sudo -u zimbra /opt/zimbra/bin/zmcontrol start

 # Create a txt file in the backup directory that'll contain the current Zimbra
 # server version. Handy for knowing what version of Zimbra a backup can be restored to.
 sudo -u zimbra zmcontrol -v > /backup/zimbra/conf/zimbra_version.txt
 # or examine your /opt/zimbra/.install_history
 
 # Create archive of backed-up directory for offsite transfer
 # cd /backup/zimbra
 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

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 sudo on your operating system has problems and some services don't start correctly. If that's the case use 'su -' in the following format for the commands:

su - zimbra -c "zmcontrol start"


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.
#
# 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 sofrware (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. Recover 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/
SYNC_DIR=/srv/backup/sync/
ARCHIVEDIR=/srv/backup/dars/
TOO_MEDIA_DIR=/srv/backup/burn/

#
#--- PROGRAM OPTIONS ---# 
RSYNC_OPTS="-aHK --delete --exclude=*.pid"

#
#--- ARCHIVE NAMES ---#
BACKUPNAME="Zimbra_Backup"
BACKUPTYPE_F="FULL"	# name prefix to sort between full and diff backups
BACKUPTYPE_D="DIFF"
BACKUPDATE=`date +%d-%B-%Y`

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

CRYPT="yes"		# valid answers are "yes" or "no"
PASSDIR=/etc/zmbac/
PASSFILE="noread"

#
#--- EMAIL ADDRESS ---#
EMAIL="admin@localhost"
EMAILCC="admin@remotehost"
LOG="/var/log/zim_backup.log"

#--- SSH REMOTE DR COPY ---#
# This option will secure copy you archives to a remote server via 'scp'
DRCP="yes" 		# valid answers are "yes" or "no" 
SSHUSER="heinzg"
REMOTEHOST="172.16.184.1"
REMOTEDIR="/tmp/"

#--- 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
#
#

# 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 "$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 -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 defaults, and NO 'passphrase' !!"
		    ssh-keygen
		    echo
		    echo "copying your ID to $REMOTEHOST"
		    echo "please enter your '$SSHUSER' user password on '$REMOTEHOST' at the prompt"
		    ssh-copy-id -i /root/.ssh/id_rsa "$SSHUSER"@"$REMOTEHOST"
		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 -l "$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 -l "$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 -l $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 -l "$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 -l "$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 -l $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 -l $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 -l $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 -l "$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 -l "$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 -l $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 -l "$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 -l "$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 -l $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 -l $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 -l $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 -l "$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 -l "$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 the script:::::::::::::::::::::::::"
    echo
    ;;

    *)
    echo
    echo "use -h or --help for assistance"
    echo
    ;;

    esac
exit 0

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.

>[insert command for renaming here]

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
>[insert command for renaming here]

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.

Jump to: navigation, search