Migrating from 32 bit Centos 4.x to 64 bit Centos 5.x

Background

I wrote the script to migrate from Zimbra running on Centos 4.x 32 bit to Centos 5.x 64 bit. It has been tested using Zimbra version 5.05_GA community edition running in single server mode.

Prerequisites

  • The script must only be used to migrate the same version of Zimbra. An upgrade to Zimbra must either be done before the migration on the old server or after migration on the new server.
  • The new server needs ssh access to the old server with a /root/.ssh/id_dsa.pub key with no passphrase on the new server appended to /root/.ssh/authorized_keys2 of the old server.
  • The version of Zimbra for the new server must be downloaded and unpacked.
  • check if the precondition for the zimbra installation on the new server exists match (packages like: gmp sysstat, or other librarys (start the installation and cancel before the installation starts))
  • Enter the hostname of the server either in the /etc/hosts file or on a local DNS server. This is for Zimbra installation.
  • Ensure sendmail is stopped and any web server port clashes are avoided. Again, this if for Zimbra installation.
  • DNS entries must be changed from old to new server at some point. Perhaps the TTL can be reduced before the required changeover to reduce DNS resolution related downtime.
  • Some downtime is acceptable.

Usage

The script only needs two parameters, the directory in which it can find the Zimbra installation files for the new server and the address of the old server to pull the data from.

Example:

./zimbra_platform_migrate /root/installers/zcs-5.0.5_GA_2201.RHEL5_64.20080417032846 old.server.com

old.server.com would probably be defined in the /etc/hosts file or a local DNS server since the domain name is moving to the new server.

What it does and why

I found that only the LDAP database was binary incompatible between 32 and 64 bit. For this reason it is transfered using an LDIF dump from one server to the other.

Most of the data is simply rsync'd across. This is done in two passes, one with the source server live and a final pass with the source server stopped. This is to minimise downtime due to both servers being stopped since the initial data transfer will probably take a very long time depending on the amount of data to transfer and the network bandwidth available for the transfer. On the second pass, only minor changes should be transfered. The script pauses when it is ready to shut down the source server.

The source Zimbra server is never restarted since we probably don't want it to collect any more data once we have migrated. That is now the new server's job.

I found that I couldn't successfully copy the SSL certs so I simply delete and re-create them on the new server. If commercial certs are used then I guess they will need to be manually re-imported after the migration.

Cleaning up

  • Make sure the key is removed from the old machine's /root/.ssh/authorized_keys2 file if it is no longer required.
  • Update any Zimbra configuration settings that may still have the old IP address such as MTA trusted networks.

The script

#!/bin/bash

# Program name: zimbra_platform_migrate

#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.

#    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, see <http://www.gnu.org/licenses/>
# Copyright 2008 Simon Blandford, Onepoint Consulting Limited
# Version 1.0.0

#Zimbra platform migration script for migrating a 32 bit installation to a 64 bit installation
#or from an old platform version to a new platform version e.g. RHEL4 to RHEL5

#Prerequisites
#1) This script must be run with root privaleges
#2) The new server has key-based ssh root access to the old server

zimbraLocation="/opt/zimbra/"

function usage()
{
  echo "Usage: "`basename $0`" <zimbra install files directory> <remote host name>"
  exit 0
}

function syncfromremote()
{
  echo "Importing data directories...."
  echo "conf"
  rsync -aHz --force --delete "$sourceLocation"/conf/ "$zimbraLocation"/conf/
  echo "convertd"
  rsync -aHz --force --delete "$sourceLocation"/convertd/ "$zimbraLocation"/convertd/
  echo "db"
  rsync -aHz --force --delete "$sourceLocation"/db/ "$zimbraLocation"/db/
  echo "index"
  rsync -aHz --force --delete "$sourceLocation"/index/ "$zimbraLocation"/index/
  echo "jetty/logs"
  rsync -aHz --force --delete "$sourceLocation"/jetty/logs/ "$zimbraLocation"/jetty/logs
  echo "log"
  rsync -aHz --force --delete "$sourceLocation"/log/ "$zimbraLocation"/log/
  echo "logger/db"
  rsync -aHz --force --delete "$sourceLocation"/logger/db/ "$zimbraLocation"/logger/db/
  echo "redolog"
  rsync -aHz --force --delete "$sourceLocation"/redolog/ "$zimbraLocation"/redolog/
  echo "store"
  rsync -aHz --force --delete "$sourceLocation"/store/ "$zimbraLocation"/store/
  echo "zmstat"
  rsync -aHz --force --delete "$sourceLocation"/zmstat/ "$zimbraLocation"/zmstat/
  echo ".ssh"
  rsync -aHz --force --delete "$sourceLocation"/.ssh/ "$zimbraLocation"/.ssh/
}

if [ "$(id -u)" != "0" ]; then
  echo "Error: This script must be run as root." >&2
  exit 1
fi

if [ "$#" -ne 2 ]; then
  usage
fi

zimbraInstallDir=$1

if [ ! -f "$zimbraInstallDir"/install.sh ]; then
  echo "Error: Zimbra install script not found in $zimbraInstallDir." >&2
  exit 1
fi

remoteHostName=$2

echo "Fetching remote zimbra version information."
if ! remoteVersion=`ssh -o stricthostkeychecking=no  \
    "$remoteHostName" 'su - zimbra -c "zmcontrol -v" | awk '"'"'{ print $2; }'"'"' | egrep  -o "[^_]*_[[:alpha:]]*_[[:digit:]]*"'`; then
  echo "Error: Remote zimbra instalation not found at $remoteHostName." >&2
  exit 1
fi
sourceLocation="$remoteHostName":"$zimbraLocation"

echo "Fetching local zimbra version information."
if ! localVersion=`su - zimbra -c "zmcontrol -v" 2>/dev/null | awk '{ print $2; }' | egrep  -o "[^_]*_[[:alpha:]]*_[[:digit:]]*" `; then
  echo "Zimbra not yet installed. Installing Zimbra"
  cd "$zimbraInstallDir"
  ./install.sh --platform-override
  echo "Fetching local zimbra version information."
  localVersion=`su - zimbra -c "zmcontrol -v" | awk '{ print $2; }' | egrep  -o "[^_]*_[[:alpha:]]*_[[:digit:]]*"`
fi

echo "Comparing local and remote Zimbra versions"
 if [  "$localVersion" !=  $remoteVersion ]; then
  echo "Error: local and remote zimbra versions are different." >&2
  echo "Local version is $localVersion." >&2
  echo "Remote version is $remoteVersion." >&2
  exit 1
fi


echo "Shutting down local Zimbra."
/sbin/service zimbra stop

echo "Starting transfer from live remote server (first pass)."
echo "Some rsync errors are expected due to changing data."
syncfromremote

unset response
while [ "$response" != "yes" ]; do
  echo -n "Type \"yes\" when ready to shutdown remote server: "
  read response
  echo
done

echo "Shutting down remote Zimbra."
ssh -o stricthostkeychecking=no "$remoteHostName" '/sbin/service zimbra stop'

echo "Starting transfer from shutdown remote server (final pass)."
syncfromremote

echo "Fixing permissions"
chown zimbra.zimbra "$zimbraLocation" -R
"$zimbraLocation"/libexec/zmfixperms

echo "Removing stale pid files"
find "$zimbraLocation" -type f -name *.pid -print0 | xargs -0 rm -f

echo "Clearing ldap database"
mv "$zimbraLocation"/openldap-data/DB_CONFIG /tmp/DB_CONFIG
rm -f "$zimbraLocation"/openldap-data/*  2>&1 | grep -v "Is a directory" 1>&2
mv /tmp/DB_CONFIG "$zimbraLocation"/openldap-data/DB_CONFIG  
echo "Importing ldap database"
ssh -C -o stricthostkeychecking=no "$remoteHostName" \
  "$zimbraLocation"'/openldap/sbin/slapcat -f '" $zimbraLocation"'/conf/slapd.conf -b ""' > /tmp/LDIF
su - zimbra -c "$zimbraLocation"'/openldap/sbin/slapadd -b "" -f '"$zimbraLocation"'/conf/slapd.conf -l /tmp/LDIF'
rm -f /tmp/LDIF

echo "Deleting old SSL certs"
rm -rf "$zimbraLocation"/ssl
mkdir "$zimbraLocation"/ssl
chown zimbra:zimbra "$zimbraLocation"/ssl
chown zimbra:zimbra "$zimbraLocation"/java/jre/lib/security/cacerts
chmod 644 "$zimbraLocation"/java/jre/lib/security/cacerts
su - zimbra -c 'keytool -delete -alias my_ca -keystore '"$zimbraLocation"'/java/jre/lib/security/cacerts -storepass changeit'
#Next line is ugly hack because I always got an error using keytool
rm -f "$zimbraLocation"/mailboxd/etc/keystore
echo "Creating new SSL certs"
"$zimbraLocation"/bin/zmcertmgr createca -new
"$zimbraLocation"/bin/zmcertmgr deployca -localonly
"$zimbraLocation"/bin/zmcertmgr createcrt self -new
"$zimbraLocation"/bin/zmcertmgr deploycrt self

echo "Fixing permissions again"
chown zimbra.zimbra "$zimbraLocation" -R
"$zimbraLocation"/libexec/zmfixperms

echo "Running zimbra upgrade and zmsetup to smooth over cracks."
cd "$zimbraInstallDir"
./install.sh -s --platform-override
echo "Running zmsetup now."
"$zimbraLocation"/libexec/zmsetup.pl

echo "Done."

changes for 6.0.8 OSS Edition

To use the above script for 6.0.8 (an maybe newer 6.* editions (untestetd)) change the following lines:

echo "Clearing ldap database"
mv "$zimbraLocation"/openldap-data/DB_CONFIG /tmp/DB_CONFIG
rm -f "$zimbraLocation"/openldap-data/*  2>&1 | grep -v "Is a directory" 1>&2
mv /tmp/DB_CONFIG "$zimbraLocation"/openldap-data/DB_CONFIG  
echo "Importing ldap database"
ssh -C -o stricthostkeychecking=no "$remoteHostName" \
  "$zimbraLocation"'/openldap/sbin/slapcat -f '" $zimbraLocation"'/conf/slapd.conf -b ""' > /tmp/LDIF
su - zimbra -c "$zimbraLocation"'/openldap/sbin/slapadd -b "" -f '"$zimbraLocation"'/conf/slapd.conf -l /tmp/LDIF'
rm -f /tmp/LDIF

To:

echo "Clearing ldap database"
mv "$zimbraLocation"/data/ldap/hdb/db/DB_CONFIG /tmp/DB_CONFIG
rm -f "$zimbraLocation"/data/ldap/hdb/db/*  2>&1 | grep -v "Is a directory" 1>&2
mv /tmp/DB_CONFIG "$zimbraLocation"/data/ldap/hdb/db/DB_CONFIG
echo "Importing ldap database"
ssh -C -o stricthostkeychecking=no "$remoteHostName" \
  "$zimbraLocation"'/openldap/sbin/slapcat -F '" $zimbraLocation"'/data/ldap/config -b ""' > /tmp/LDIF
su - zimbra -c "$zimbraLocation"'/openldap/sbin/slapadd -b "" -F '"$zimbraLocation"'/data/ldap/config -l /tmp/LDIF'
rm -f /tmp/LDIF

changes for 7.0.0 Beta3 OSS Edition

#!/bin/bash

# Program name: zimbra_platform_migrate

#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.

#    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, see <http://www.gnu.org/licenses/>
# Copyright 2011 apsantos@openxange.org
# Version 1.0.1

#Zimbra platform migration script for migrating a 32 bit installation to a 64 bit installation
#or from an old platform version to a new platform version e.g. RHEL4 to RHEL5

#Prerequisites
#1) This script must be run with root privaleges
#2) The new server has key-based ssh root access to the old server

zimbraLocation="/opt/zimbra/"

function usage()
{
  echo "Usage: "`basename $0`" <zimbra install files directory> <remote host name>"
  exit 0
}

function syncfromremote()
{
  echo "Importing data directories...."
  echo "conf"
  rsync -aHz --force --delete "$sourceLocation"/conf/ "$zimbraLocation"/conf/
  echo "convertd"
  rsync -aHz --force --delete "$sourceLocation"/data/ "$zimbraLocation"/data/
  echo "db"
  rsync -aHz --force --delete "$sourceLocation"/db/ "$zimbraLocation"/db/
  echo "index"
  rsync -aHz --force --delete "$sourceLocation"/index/ "$zimbraLocation"/index/
  echo "jetty/logs"
  rsync -aHz --force --delete "$sourceLocation"/jetty/logs/ "$zimbraLocation"/jetty/logs
  echo "log"
  rsync -aHz --force --delete "$sourceLocation"/log/ "$zimbraLocation"/log/
  echo "logger/db"
  rsync -aHz --force --delete "$sourceLocation"/logger/db/ "$zimbraLocation"/logger/db/
  echo "redolog"
  rsync -aHz --force --delete "$sourceLocation"/redolog/ "$zimbraLocation"/redolog/
  echo "store"
  rsync -aHz --force --delete "$sourceLocation"/store/ "$zimbraLocation"/store/
  echo "zmstat"
  rsync -aHz --force --delete "$sourceLocation"/zmstat/ "$zimbraLocation"/zmstat/
echo "memcached"
  rsync -aHz --force --delete "$sourceLocation"/memcached/ "$zimbraLocation"/memcached/
  echo ".ssh"
  rsync -aHz --force --delete "$sourceLocation"/.ssh/ "$zimbraLocation"/.ssh/
}

if [ "$(id -u)" != "0" ]; then
  echo "Error: This script must be run as root." >&2
  exit 1
fi

if [ "$#" -ne 2 ]; then
  usage
fi

zimbraInstallDir=$1

if [ ! -f "$zimbraInstallDir"/install.sh ]; then
  echo "Error: Zimbra install script not found in $zimbraInstallDir." >&2
  exit 1
fi

remoteHostName=$2

echo "Fetching remote zimbra version information."
if ! remoteVersion=`ssh -o stricthostkeychecking=no  \
    "$remoteHostName" 'su - zimbra -c "zmcontrol -v" | awk '"'"'{ print $2; }'"'"' | egrep  -o "[*_[[:alpha:]]*_[[:digit:]]*"'`; then
  echo "Error: Remote zimbra instalation not found at $remoteHostName." >&2
  exit 1
fi
sourceLocation="$remoteHostName":"$zimbraLocation"

echo "Fetching local zimbra version information."
if ! localVersion=`su - zimbra -c "zmcontrol -v" 2>/dev/null | awk '{ print $2; }' | egrep  -o "[*_[[:alpha:]]*_[[:digit:]]*" `; then
  echo "Zimbra not yet installed. Installing Zimbra"
  cd "$zimbraInstallDir"
  ./install.sh --platform-override
  echo "Fetching local zimbra version information."
  localVersion=`su - zimbra -c "zmcontrol -v" | awk '{ print $2; }' | egrep  -o "[*_[[:alpha:]]*_[[:digit:]]*"`
fi

echo "Comparing local and remote Zimbra versions"
 if [  "$localVersion" !=  $remoteVersion ]; then
  echo "Error: local and remote zimbra versions are different." >&2
  echo "Local version is $localVersion." >&2
  echo "Remote version is $remoteVersion." >&2
  exit 1
fi


echo "Shutting down local Zimbra."
/sbin/service zimbra stop

echo "Starting transfer from live remote server (first pass)."
echo "Some rsync errors are expected due to changing data."
syncfromremote

unset response
while [ "$response" != "yes" ]; do
  echo -n "Type \"yes\" when ready to shutdown remote server: "
  read response
  echo
done

echo "Shutting down remote Zimbra."
ssh -o stricthostkeychecking=no "$remoteHostName" '/sbin/service zimbra stop'

echo "Starting transfer from shutdown remote server (final pass)."
syncfromremote

echo "Fixing permissions"
chown zimbra.zimbra "$zimbraLocation" -R
"$zimbraLocation"/libexec/zmfixperms

echo "Removing stale pid files"
find "$zimbraLocation" -type f -name *.pid -print0 | xargs -0 rm -f

echo "Clearing ldap database"
mv "$zimbraLocation"/data/ldap/hdb/db/DB_CONFIG /tmp/DB_CONFIG
rm -f "$zimbraLocation"/data/ldap/hdb/db/*  2>&1 | grep -v "Is a directory" 1>&2
mv /tmp/DB_CONFIG "$zimbraLocation"/data/ldap/hdb/db/DB_CONFIG
echo "Importing ldap database"
ssh -C -o stricthostkeychecking=no "$remoteHostName" \
  "$zimbraLocation"'/openldap/sbin/slapcat -F '" $zimbraLocation"'/data/ldap/config -b ""' > /tmp/LDIF
su - zimbra -c "$zimbraLocation"'/openldap/sbin/slapadd -b "" -F '"$zimbraLocation"'/data/ldap/config -l /tmp/LDIF'
rm -f /tmp/LDIF


echo "Deleting old SSL certs"
rm -rf "$zimbraLocation"/ssl
mkdir "$zimbraLocation"/ssl
chown zimbra:zimbra "$zimbraLocation"/ssl
chown zimbra:zimbra "$zimbraLocation"/java/jre/lib/security/cacerts
chmod 644 "$zimbraLocation"/java/jre/lib/security/cacerts
su - zimbra -c 'keytool -delete -alias my_ca -keystore '"$zimbraLocation"'/java/jre/lib/security/cacerts -storepass changeit'
#Next line is ugly hack because I always got an error using keytool
rm -f "$zimbraLocation"/mailboxd/etc/keystore
echo "Creating new SSL certs"
"$zimbraLocation"/bin/zmcertmgr createca -new
"$zimbraLocation"/bin/zmcertmgr deployca -localonly
"$zimbraLocation"/bin/zmcertmgr createcrt self -new
"$zimbraLocation"/bin/zmcertmgr deploycrt self

echo "Fixing permissions again"
chown zimbra.zimbra "$zimbraLocation" -R
"$zimbraLocation"/libexec/zmfixperms

echo "Running zimbra upgrade and zmsetup to smooth over cracks."
cd "$zimbraInstallDir"
./install.sh -s --platform-override
echo "Running zmsetup now."
"$zimbraLocation"/libexec/zmsetup.pl

echo "Done."

additional links

change servername

change domain (zmprov -l renameDomain olddomain.local newdomain.real)

Verified Against: Zimbra 5.05_GA community edition running in single server mode Date Created: 7/29/2008
Article ID: https://wiki.zimbra.com/index.php?title=Migrating_from_32_bit_Centos_4.x_to_64_bit_Centos_5.x Date Modified: 2015-03-24



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