(dv) 3.5:Restore data

  • This page was last modified on March 27, 2012, at 11:41.
The (mt) Community Wiki is a collaborative project. Any (mt) Media Temple customer or employee may contribute. Not all articles and/or content have been tested for accuracy by (mt) Media Temple.

For officially moderated and tested articles, be sure to visit our KnowledgeBase.

From (mt) Community Wiki

This article is only relevant for the (dv) Dedicated-Virtual 3.5; if you have a (dv) Dedicated-Virtual 4.0, a similar script can be found in the following article: (dv) 4.0:Restore Data after Reverting to Default

Contents


This script is run completely at YOUR OWN RISK.

You should only use the script AFTER you have removed all exploited code and ensured that all hacks have been removed.

(mt) Media Temple does not troubleshoot re-installs nor hacked servers.

Overview

If your (dv) Dedicated-Virtual Server has not been customized in any way and you have only used the Plesk Control Panel to set up your sites, then you can use the following script to quickly restore all your data after you have reinstalled your VPS. For more information, please this article: (dv):Reinstall_server.

Requirements

Instructions

We insist that if you wish to utilize this script, you first make a full Snapshot Backup of your server AFTER you complete the re-install and BEFORE you restore data. This will take a complete image of your server that can restore it to the exact state it was in, just prior to taking the Snapshot.

  • Save the following file as dvrestore.sh
  • Upload it to your server.
  • Set its permissions to 755.
  • Run it through SSH by typing the following command:
'./dvrestore.sh'

  • If you have performed multiple reinstalls, you can specify which directory you are restoring from. For example:
'./dvrestore.sh /old/old/old'


The script will start off by doing a series of checks to validate the server. It will then ask you some questions about any possibly suspicious content that the script is going to restore before it actually performs the restore.

The restore script will copy all the files that were saved in "/old" and move them back to the appropriate directory with the standard permissions and owners. It will also automatically restore all your previous Plesk settings. Although this script has been highly tested, it is hard to predict if any unique cases may cause it to behave unexpectedly.

dvrestore.sh
#!/bin/bash

##Define important variables:

[[ $1 == "" ]] && RESTORE_DIR=/old || RESTORE_DIR=$1 ;

BACKUP_DIR=/opt/mt_restore_backup ;

IMPORTANT_FILES=( /etc/passwd  \
/etc/group \
/etc/shadow  \
/etc/httpd/conf.d/zz010_psa_httpd.conf \
/usr/local/psa/admin/htdocs/domains/databases/phpMyAdmin/libraries/config.default.php  \
/etc/psa/.webmail.shadow  \
/etc/psa/.psa.shadow );

IMPORTANT_DIRECTORIES=( /var/www/vhosts \
/var/qmail \
/var/named/run-root/etc \
/var/spool/cron  \
/var/lib/mysql \
/var/lib/psa/dumps  \
/etc/psa-horde );

BACKUP_DIRS=(   /etc \
/vhosts \
/qmail \
/run-root \
/conf.d  \
/PSAphpMyAdmin \
/horde  \
/crons  \
/certificates \
/mysql \
/dumps );


echo'';
echo 'PLEASE READ CAREFULLY....';
echo '';
echo '';
echo "This script is for automatically restoring Plesk configuration and domain data on (dv)s that were forced to re-install becaused they were root hacked. This script will not work for customized (dv)s or (dv)s provisioned without Plesk.  The intention of this script is to assist (dv)s that were rooted but appeared to still be running normally after a re-install. If you needed to re-install because you did something like 'rm -rf /*' this script will not help you. When restoring from rooted (dv)s, please carefully audit all web viewable files in '/old/var/www/vhosts/(domain)/(httpdocs|httpsdocs|cgi-bin)'  and ESPECIALLY '/var/spoon/cron/*' files before using this script.  It is very common to see malicious scripts added to a domain files or a cronjob added to re-hack your server. ";
echo '';


read -p 'Do you wish continue with the restore? YES/no : ' USESCRIPT
if [ "$USESCRIPT" != "YES"  ]; then
echo  'Bye!!';
exit 0;
fi


##Checking for the existance of all the files and direcotries we will be using to avoid any unexpected results.

echo "";
echo "Running Restore pre-check.....";
sleep 2;
echo "";
echo "checking for $RESTORE_DIR";
sleep 2;

if [ ! -d $RESTORE_DIR ]; then
echo "No $RESTORE_DIR directory!";
echo 'Sorry. There is nothing to restore.'
exit 0;
else
echo "$RESTORE_DIR found.";
fi

echo"";
echo"";

echo "Checking disk space..."
sleep 2;
DISKSPACE=$( df | awk '/^\/dev/{print $5}' | sed -e "s/\%//" );

if [ ${DISKSPACE} -gt 50 ]; then
echo "${DISKSPACE} used. There is not enough disk space left to restore your data.  You will need to temporarily upgrade to get more space before you can continue with the restore script.";
echo "Aborting Restore";
exit 0;
else
echo "Only ${DISKSPACE} disk space used, continuing...";
fi

echo;
echo;

echo "Checking for important files in /old and current root...";
sleep 2;
for FILE in ${IMPORTANT_FILES[@]}
do
if [ ! -f ${RESTORE_DIR}${FILE} ]; then

echo "${RESTORE_DIR}$FILE not found.";
echo 'Unable to continue automatically.  Server back-up incomplete or original server was customized.'
exit 0;
#	else
#		echo "${RESTORE_DIR}$FILE found.";
fi

if [ ! -f ${FILE} ]; then

echo "$FILE not found.";
echo 'Unable to continue automatically.  Current server was customized or is missing important files.'
exit 0;
#	else
#		echo "$FILE found.";
fi
done

echo"";
echo "";


echo "Checking for important directories in /old and current root...";
sleep 2;
for DIRECTORY in ${IMPORTANT_DIRECTORIES[@]}
do

if [ ! -d ${RESTORE_DIR}${DIRECTORY} ]; then
echo "${RESTORE_DIR}$DIRECTORY not found!!";
echo 'Unable to continue automatically.  Server back-up incomplete or original server was customized.'
exit 0;
#	else
#		echo "${RESTORE_DIR}$DIRECTORY found.";
fi

if [ ! -d ${DIRECTORY} ]; then
echo "$DIRECTORY not found.";
echo 'Unable to continue automatically.  Current server was customized or is missing important files.'
exit 0;
#	else
#		echo "$DIRECTORY found.";
fi
done


##Checking password file; we will be partially restoring for anything bad.
echo;
echo;


echo 'Checking old password file for suspicious users.';
sleep 2;

##First, we look for root alias accounts.

ROOTALIAS=( $(awk -F: '$3 ~/^0$/ && $1 !~/^root$/' ${RESTORE_DIR}/etc/passwd) ) ;

if [ ${#ROOTALIAS[@]}  -ge  1  ]; then
echo "Found root aliases..."
for FOUND in  ${ROOTALIAS[@]}
do
echo "Found $FOUND.";
done
echo "Generally, this is a bad thing.  Please remove these users from the old password file before restoring.";
echo "Restore aborted.";
exit 0
else
echo "No root aliases found.";

fi
echo;

##Next, we look for shell users that do not appear to have been added by Plesk. Remember '/bin/false' shell allows for FTP login and SSH proxy.

CUSTOMUSERS=( $(awk -F: '$3 !~/^0$/ &&  $6 !~/\/var\/www\/vhosts/ && $1 !~/^(mysql)$/ && $7 ~/sh$|\/bin\/false$/' ${RESTORE_DIR}/etc/passwd ) );

if [ ${#CUSTOMUSERS[@]}  -ge  1  ]; then
echo "Found custom users..."
for FOUND in  ${CUSTOMUSERS[@]}
do
echo "Found $FOUND.";
done
read -p 'Are these legitimate users you added to the system? (Remember "/bin/false" shell allows for FTP login and SSH proxy.)   YES/no : ' USERANSWER
if [ "$USERANSWER" != "YES"  ]; then
echo "Please remove these users from the old password file before restoring.";
echo "Restore aborted.";
exit 0
fi
else
echo "No custom users found.";

fi
sleep 2;
echo


echo 'Checking for root owned files in web viewable directies.....';
sleep 2;
ROOTFILE=( $( cd ${RESTORE_DIR}/var/www/vhosts ;  find */httpdocs/ */httpsdocs/ */cgi-bin/  -user root ! -regex .*plesk-stat.*  ) );

if  [ ${#ROOTFILE[@]} -ge 1  ]; then
echo "Found root owned files in web viewable directories...."
for FOUND in ${ROOTFILE[@]}
do
echo "$FOUND";
done
read -p 'Are these legitimate root owned files? YES/no : ' ROOTFILEANSWER
if [ "$ROOTFILEANSWER" != "YES"  ]; then
echo "Please remove these files before restoring.";
echo "Restore aborted.";
exit 0
fi
else
echo "No root files found in web viewable directories.";


fi

echo "";
echo "";


echo "Checking for suspicious crontabs...";
sleep 2
for CRONT in $(ls -1 ${RESTORE_DIR}/var/spool/cron)
do
echo "crontab for $CRONT";
cat ${RESTORE_DIR}/var/spool/cron/$CRONT;
echo;
done

read -p 'Any suspicious crontab entries? yes/NO : ' ANSWERCRON
if [ "$ANSWERCRON" != "NO"   ]; then
echo 'Please remove the suspicious entries, then re-run this script.';
exit 0;
fi

echo "Pre-cehck complete. Creating back-up directories....."
sleep 2;

##Creating back up directories for current files on the newly restored (dv).

echo "";
echo "";
if [ ! -d ${BACKUP_DIR} ]; then
mkdir ${BACKUP_DIR};
echo "Created ${BACKUP_DIR}";
else
echo "${BACKUP_DIR} already exists.";
fi

for BACKUP_DIR_C in  ${BACKUP_DIRS[@]}
do
if [ ! -d ${BACKUP_DIR}${BACKUP_DIR_C} ]; then
mkdir ${BACKUP_DIR}$BACKUP_DIR_C;
echo "Created ${BACKUP_DIR}$BACKUP_DIR_C";

else
FOUND='set';
#		echo "${BACKUP_DIR}$BACKUP_DIR_C already exists.";
fi
done
#sleep 2;
echo '';
if [ "$FOUND" == "set"  ]; then
read -p 'Possible pre-existing back-up. Do you want to move the older back-up and continue? YES/no : ' ANSWER
if [ "$ANSWER" != "YES"  ]; then
echo "Your response was 'no.' Restore aborted. Please move or remove existing back-up directory or change \$BACKUP_DIR variable.";
exit 0
else
DATE=$( date | sed -e "s/\ /_/g" );
mv ${BACKUP_DIR} ${BACKUP_DIR}${DATE};
mkdir ${BACKUP_DIR}
echo "Old back up saved in /opt/mt_restore_backup${DATE}";
for BACKUP_DIR_C in  ${BACKUP_DIRS[@]}
do
mkdir ${BACKUP_DIR}${BACKUP_DIR_C};
echo "Created ${BACKUP_DIR}${BACKUP_DIR_C}";
done

echo "Back-up directories ready. Copying files...";
fi
else
echo "Back-up directories ready. Copying files....";
fi

echo '';

##copying over files to back up directories

echo 'Saving system user files...';
cp -p /etc/passwd /etc/group /etc/shadow ${BACKUP_DIR}/etc/;

echo 'Saving vhosts directories...';
cp -Rdp /var/www/vhosts/* ${BACKUP_DIR}/vhosts;

echo 'Saving qmail files...';
/etc/init.d/qmail stop;
cp -Rdp /var/qmail/* ${BACKUP_DIR}/qmail;
/etc/init.d/qmail start;


echo 'Saving bind files...';
cp -Rdp /var/named/run-root/etc/* ${BACKUP_DIR}/run-root;
cp -Rdp /var/named/run-root/var/* ${BACKUP_DIR}/run-root;

echo 'Saving Plesk Apache config...';
cp -p /etc/httpd/conf.d/zz010_psa_httpd.conf ${BACKUP_DIR}/conf.d/;

echo 'Saving phpMyAdmin config...';
cp -p /usr/local/psa/admin/htdocs/domains/databases/phpMyAdmin/libraries/config.default.php ${BACKUP_DIR}/PSAphpMyAdmin/;

echo 'Saving Horde config...';
cp -Rdp /etc/psa-horde/* ${BACKUP_DIR}/horde;
cp /etc/psa/.webmail.shadow ${BACKUP_DIR}/horde/;

echo 'Saving certificate files...';
cp -p /usr/local/psa/var/certificates/* ${BACKUP_DIR}/certificates/;

echo 'Saving crontabs...';
cp -dp /var/spool/cron/* ${BACKUP_DIR}/crons;

echo 'Saving MySQL databases...';
/etc/init.d/mysqld stop;
cp -Rdp /var/lib/mysql/* ${BACKUP_DIR}/mysql;
/etc/init.d/mysqld start;

echo 'Saving psa shadow file...';
cp -p /etc/psa/.psa.shadow ${BACKUP_DIR}/;

echo 'Saving psa dump files...';
touch /var/lib/psa/dumps/place_holder;
cp -Rdp /var/lib/psa/dumps/* ${BACKUP_DIR}/dumps;

read -p 'Back-ups complete. Ready for final sync? (You may want to double-check that the script backed up the current config correctly.)  YES/no : ' ANSWERTWO
if [ "$ANSWERTWO" != "YES"  ]; then
echo "Your response was 'no.' Restore aborted.";
exit 0
else
echo "Syncing with ${RESTORE_DIR} files...";
fi


##Contructing new system user files which will be a combination of the one in the /old and the current one since Plesk does not keep some important uid's and gid's consistant.  If we didn't do this, Plesk may encounter errors

echo "Syncing system users (except root) ..."
echo "Creating new password file in /tmp...";
sed -e  "s/^psaadm:.*$/$(cat ${BACKUP_DIR}/etc/passwd | egrep ^psaadm: | sed -e  s'/\//\\\//g' )/" \
-e  "s/^psaftp:.*$/$(cat ${BACKUP_DIR}/etc/passwd | egrep ^psaftp: | sed -e  s'/\//\\\//g' )/"  ${RESTORE_DIR}/etc/passwd > /tmp/.newpasswdf;


echo "Creating new group file in /tmp...";
sed -e  "s/^psaadm:.*$/$(cat ${BACKUP_DIR}/etc/group | egrep ^psaadm: | sed -e  s'/\//\\\//g' )/"  \
-e  "s/^psaftp:.*$/$(cat ${BACKUP_DIR}/etc/group | egrep ^psaftp: | sed -e  s'/\//\\\//g' )/"  \
-e  "s/^psaserv:.*$/$(cat ${BACKUP_DIR}/etc/group | egrep ^psaserv: | sed -e  s'/\//\\\//g' )/" \
-e  "s/^psacln:.*$/$(cat ${BACKUP_DIR}/etc/group | egrep ^psacln: | sed -e  s'/\//\\\//g' )/" ${RESTORE_DIR}/etc/group > /tmp/.newgroupf;


echo "Creating new shadow file in /tmp...";
sed "s/^root:.*$/$(cat ${BACKUP_DIR}/etc/shadow | egrep ^root: | sed -e s'/\//\\\//g')/" ${RESTORE_DIR}/etc/shadow > /tmp/.newshadowf;

read -p 'Review tmp sys user files?  yes/NO : ' ANSWERTHREE
if [ "$ANSWERTHREE" != "NO"  ]; then
echo "Your response was 'yes.' Restore aborted.";
exit 0;
else
echo "Syncing with /tmp files...";
fi

##Syncing the tmp new system user database files with active database files and cleaning up the tmp files.

cat /tmp/.newpasswdf > /etc/passwd;
cat /tmp/.newgroupf > /etc/group;
cat /tmp/.newshadowf > /etc/shadow;
rm -f /tmp/.newpasswdf /tmp/.newgroupf /tmp/.newshadowf;



##Syncing everything else with /old.


echo 'Syncing vhosts...';
/bin/cp -Rdpf ${RESTORE_DIR}/var/www/vhosts/* /var/www/vhosts;

##Fixing the mixed up psa* groups.
echo 'Correcting folder owners...';
find /var/www/vhosts/  -gid $( awk -F: '$1 ~/^psaserv$/ {print $3}' ${RESTORE_DIR}/etc/group ) -exec chgrp -h psaserv {} \; ;
find /var/www/vhosts/ -gid $( awk -F: '$1 ~/^psacln$/ {print $3}' ${RESTORE_DIR}/etc/group  ) -exec chgrp -h psacln {} \; ;
for PSAUSER in $(awk -F: '$6 ~/\/var\/www\/vhosts/{print $1}' /etc/passwd );
do
usermod -g psacln $PSAUSER;
done

##Simple copying of everything else
echo 'Syncing qmail files...';
/etc/init.d/qmail stop;
/bin/cp -Rdpf ${RESTORE_DIR}/var/qmail/alias/* /var/qmail/alias/;
/bin/cp -Rdpf ${RESTORE_DIR}/var/qmail/boot/* /var/qmail/boot/;
/bin/cp -Rdpf ${RESTORE_DIR}/var/qmail/control/* /var/qmail/control/;
/bin/cp -Rdpf ${RESTORE_DIR}/var/qmail/mailnames/* /var/qmail/mailnames/;
/bin/cp -Rdpf ${RESTORE_DIR}/var/qmail/plugins/* /var/qmail/plugins/;
/bin/cp -Rdpf ${RESTORE_DIR}/var/qmail/queue/* /var/qmail/queue/;
/bin/cp -Rdpf ${RESTORE_DIR}/var/qmail/users/* /var/qmail/users/;

echo 'Syncing bind files...';
/bin/cp -Rdpf ${RESTORE_DIR}/var/named/run-root/etc/* /var/named/run-root/etc
/bin/cp -Rdpf ${RESTORE_DIR}/var/named/run-root/var/* /var/named/run-root/var

echo 'Syncing Plesk Apache config...';
cat ${RESTORE_DIR}/etc/httpd/conf.d/zz010_psa_httpd.conf > /etc/httpd/conf.d/zz010_psa_httpd.conf;

echo 'Syncing phpMyAdmin config...';
cat ${RESTORE_DIR}/usr/local/psa/admin/htdocs/domains/databases/phpMyAdmin/libraries/config.default.php > /usr/local/psa/admin/htdocs/domains/databases/phpMyAdmin/libraries/config.default.php

echo 'Syncing Horde config...';
cp -Rdpf ${RESTORE_DIR}/etc/psa-horde/* /etc/psa-horde
cat ${RESTORE_DIR}/etc/psa/.webmail.shadow > /etc/psa/.webmail.shadow;

echo 'Syncing Certificate files...';
rm -f /usr/local/psa/var/certificates/*;
cp -dpf ${RESTORE_DIR}/usr/local/psa/var/certificates/* /usr/local/psa/var/certificates;

echo 'Syncing crontabs...';
/bin/cp -pf ${RESTORE_DIR}/var/spool/cron/* /var/spool/cron;

echo 'Syncing databases...';
/etc/init.d/mysqld stop;
rm -rf /var/lib/mysql/*;
/bin/cp -Rdpf ${RESTORE_DIR}/var/lib/mysql/* /var/lib/mysql;

echo 'Syncing Plesk admin pass...';
cat ${RESTORE_DIR}/etc/psa/.psa.shadow > /etc/psa/.psa.shadow;

echo 'Syncing Plesk dump files...';
touch ${RESTORE_DIR}/var/lib/psa/dumps/place_holder;
cp -Rdpf ${RESTORE_DIR}/var/lib/psa/dumps/* /var/lib/psa/dumps;
#fixing dump file owners
find /var/lib/psa/dumps/ -uid $( awk -F: '$1 ~/^psaadm$/ {print $3}' ${RESTORE_DIR}/etc/passwd  ) -exec chown psaadm:psaadm {} \; ;


echo '';
echo '';
echo 'If you only saw two errors about a special file, you should be good!';
echo '';
echo '';
echo 'Restarting services...';
/etc/init.d/mysqld start;
/etc/init.d/httpd restart;
/etc/init.d/qmail start;
/etc/init.d/xinetd restart;
/etc/init.d/courier-imap restart;
/etc/init.d/named restart;
/etc/init.d/psa restart;
/usr/local/psa/admin/sbin/mchk --with-spam;
echo '';
echo 'Restore complete.  RESET PLESK ADMIN PASSWORD ASAP!!!';

If the above script fails to work, you will have to manually move the data back yourself. The easiest way to do this is to first go through Plesk and set up all your clients, domains, email accounts again. This will make sure all the server configurations and permissions are correct. After that, you can restore the data by copying it from the matching directories in ‘/old’ directory.

Items to note:

' /var/www/vhosts/(domain name) ' contains the files for each domain you see when logging in through FTP.

' /var/qmail/mailnames/(domain name)/(account name)/Maildir ' is the directory where email files are stored.

Recover databases

Recovering databases can be a bit more complicated. In many cases, just copying the files will not work. To get your old databases you can try running the following script:

dbrestore.sh
#!/bin/bash


DBNAME=$1;
DUMPNAME=" ${DBNAME}_$(  date | sed -e 's/\s/_/g'  ).sql";
OLD_DIR='/old';

if [ "$DBNAME" == ''  ]; then

echo "Please supply a database to backup"
echo "Example command:";
echo "./dbrestore.sh (database name)";
echo "";
echo "Or to list all old databases:";
echo "./dbrestore --list-dbs";

exit 0;
elif [  "$DBNAME" == '--list-dbs'   ]; then
ls -1 $OLD_DIR/var/lib/mysql | awk '!/^ib/';
exit 0;
fi

if [ ! -d "$OLD_DIR/var/lib/mysql/$DBNAME"  ]; then

echo "Database directories for $DBNAME do not exist in $OLD_DIR...."
exit 0;

fi

echo "Starting MySQL instance..."

/usr/bin/mysqld_safe --datadir=$OLD_DIR/var/lib/mysql --log-error=/tmp/mt_restore_mysql.log  --pid-file=/tmp/mysql_pid --skip-external-locking --skip-networking --socket=/tmp/mysql_sock 2>&1 > /dev/null  &

sleep 5;

echo -n "MySQL started with PID:  ";
cat /tmp/mysql_pid ;
echo "";
echo "Exporting backup of $DBNAME to $DUMPNAME...";


/usr/bin/mysqldump --socket=/tmp/mysql_sock  --add-drop-table -u admin -p`cat $OLD_DIR/etc/psa/.psa.shadow` $DBNAME > $DUMPNAME;


kill -15 $( cat /tmp/mysql_pid );
sleep 5;

This script will create a temporary second MySQL instance on your server that will access the old databases directories and do a standard MySQL dump of the database you specify. It will also list all the old databases you had set up by specifying the '--list-dbs' flag. You can then import this database dump by following the import instructions in the following (mt) Wiki article: (dv):Export and import MySQL databases.

DO NOT restore the mysql, psa, phpmyadmin and horde databases. These contain old information that will conflict with your new server.

Supplemental resources