Improved FTP Backup for WordPress

This script backups both the database and files of a WordPress blog into a remote FTP server (while keeping a local copy). It’s an update of my WordPress Backup to FTP script. The main changes are auto-detecting database settings and better support for caching plugins (specifically WP-Cache). The new version makes it easier to backup multiple WordPress blogs to the same FTP server.

Usage is pretty simple after a short initial configuration. First, save the the script and make it executable:

chmod +x wp-backup

(assuming you saved it under the name wp-backup). After saving it edit the file with your favorite editor and set the 5 configuration variable to whatever is appropriate for you. BACKUP_DIR is the folder to save the local backups to. FTP_HOST, FTP_USER, FTP_PASS control the FTP host, username and password, respectively, for the remote backup server. FTP_BACKUP_DIR sets the folder on the FTP server to save the remote backup to.

Now that the initial configuration is done, all you need to do is execute the script and give the path to the blog as an argument. For example:

./wp-backup /home/someuser/myblog

And that it, the script will backup your files (excluding cache) and database to both a local and remote locations. This allows using the same script to backup multiple WordPress blogs, unlike the previous script which had to be modified for each blog.

And now the script itself:

#!/bin/bash
 
# Copyright 2008, 2010 Guy Rutenberg <http://www.guyrutenberg.com/contact-me>
# WordPress FTP backup 2.0
#
# Easily backup wordpress instances via ftp.
#
# Change Log:
# ===========
# 2.0:
#  - Auto-detect database settings.
#  - Exclude cache data from backups.

BACKUP_DIR=
FTP_HOST=
FTP_USER=
FTP_PASS=
FTP_BACKUP_DIR=

# end of configuration - you probably don't need to touch anything below

PROG=`basename "$0"`
print_usage () {
    echo "USAGE: ${PROG} [options] BLOG_ROOT"
    echo "Backup a WordPress blog"
}

print_help ()  {
    print_usage
    cat << EOF
 
Options:
    -h, --help          show this help message and exit
 
EOF
}

TEMP=`getopt -o h --long help -n "$PROG" -- "$@"`
if (($?)); then
    print_usage
    exit 1
fi

eval set -- "$TEMP"
 
while true ; do
    case "$1" in
        -h|--help) print_help; exit ;;
        --) shift; break;;
    esac
done

if [ -z "$1" ]
then
 print_usage > /dev/stderr
 exit 1
fi

BLOG_DIR=$1
DB_NAME=`echo "<?php require_once(\"${BLOG_DIR}/wp-config.php\"); echo DB_NAME;" | php`
DB_USER=`echo "<?php require_once(\"${BLOG_DIR}/wp-config.php\"); echo DB_USER;" | php`
DB_PASS=`echo "<?php require_once(\"${BLOG_DIR}/wp-config.php\"); echo DB_PASSWORD;" | php`
DB_HOST=`echo "<?php require_once(\"${BLOG_DIR}/wp-config.php\"); echo DB_HOST;" | php`

BLOG_DIR=`dirname "$BLOG_DIR"`/`basename "$BLOG_DIR"`
BACKUP_DIR=`dirname "$BACKUP_DIR"`/`basename "$BACKUP_DIR"`

echo -n "dumping database... "
DUMP_NAME=${DB_NAME}-$(date +%Y%m%d).sql.bz2
mysqldump --user=${DB_USER} --password=${DB_PASS} --host=${DB_HOST} \
 --databases ${DB_NAME} \
 | bzip2 -c > ${BACKUP_DIR}/${DUMP_NAME}
if [ "$?" -ne "0" ]; then
	echo "failed!"
	exit 1
fi
echo "done"
 
echo -n "Creating tarball... "
TAR_NAME=${BLOG_DIR##*/}-$(date +%Y%m%d).tar.bz2
tar -cjf ${BACKUP_DIR}/${BLOG_DIR##*/}-$(date +%Y%m%d).tar.bz2 --exclude cache ${BLOG_DIR}
if [ "$?" -ne "0" ]; then
	echo "failed!"
	exit 2
fi
echo "done"
 
echo -n "Uploading SQL dump and tarball to FTP... "
lftp -u ${FTP_USER},${FTP_PASS} ${FTP_HOST} <<EOF
cd "${FTP_BACKUP_DIR}"
put "${BACKUP_DIR}/${DUMP_NAME}"
put "${BACKUP_DIR}/${TAR_NAME}"

EOF
if [ "$?" -ne "0" ]; then
	echo "failed!"
	exit 3
fi
echo "done"

80 thoughts on “Improved FTP Backup for WordPress”

  1. Thank you, this is an awesome script! Unfortunatley, it only allows one backup a day… how would one modify it to allow hourly backups?

    I assume it would be by modifying (date +%Y%m%d) to include the time?

  2. Thanks for the great script, not sure if this is an issue with my host [GoDaddy] but I seem to get the following response:

    Set-Cookie: bb2_screener_=1268525451+; path=/
    Content-type: text/html

    when the script tries to run the DB_NAME / DB_USER assignments through the portion of the script. Not sure what I am doing wrong, and running the echo command straight from shell produces same result.

    A workaround I guess would be to manually specify the DB info [as in your old version of script] but this defeats the point of a nice “automatic” detection for multiple-WP installs.

    Thanks!

  3. Do you have a fully functional shell on your GoDaddy server? Past experience teach taught me that GoDaddy doesn’t provide a full shell access, which makes running many scripts impossible (and probably this one too).

  4. actually after some long trial and error it would seem that the following part of script (for all 4 variables)

    DB_HOST=`echo “<?php include(\"${BLOG_DIR}/wp-config.php\"); echo DB_HOST;" | php`

    the php include part was returning some kind of header information in addition to the DB_HOST variable and therefore once I stripped that out by adding the following lines underneath it seemed to work.

    DB_HOST=`echo "<?php include(\"${BLOG_DIR}/wp-config.php\"); echo DB_HOST;" | php`
    DB_HOST=`echo $DB_HOST | tr -d '\r\n'`
    DB_HOST=${DB_HOST##* }

    Now on to find lftp alternative that works with GoDaddy *sigh*

  5. I created an .exe file with the sript you provide and when trying to run it I got this message:

    “The version of this file is not compatible with the version of Windows you’re running. Check your computer’s system information to see whether you need an x86 (32-bit) or x64 (64-bit) version of the program and then contact the software publisher”.

    My OS is Windows 7 – x64

    Any insight and am I doing everything right?

    Thanks.

  6. This is a bash script, how did you turn it into an exe?
    Anyway, you’ll need bash in order to run it (which probably means you’ll need some sort of Linux or BSD).

  7. This allows using the same script to backup multiple WordPress blogs, unlike the previous script which had to be modified for each blog.

    Does this mean there’s support for WPMU and Multiple DBs?

    If so, is there any other setup info we need to do to make it work?

  8. I meant that the script can be used to backup multiple regular WP blogs. I’m not familiar enough with WPMU to be sure, but I think it might work. Just try it. I don’t think it will work with multiple dbs serving one installation.

  9. Hello Guy,

    Can you give me so direction on how to solve this error?

    dumping database… ./wp-backup: line 72: ${BACKUP_DIR}/${DUMP_NAME}: ambiguous redirect
    mysqldump: unknown option ‘-2’
    failed!

    Your previous WP FTP script is working quite well on the same server.

    Thank you.

  10. Pingback: Kurortmeinung.de
  11. Hi Guy

    Same error
    dumping databaseā€¦ ./wp-backup: line 72: ${BACKUP_DIR}/${DUMP_NAME}: ambiguous redirect
    mysqldump: unknown option ā€˜-2ā€²
    failed!

    Manually ran the script for the echo DB_NAME bit and it may be wordpress v3.0 call wp-settings.php then it call something else and never actually ECHO DB_NAME.

    Hope this is making sense.

    Cheers
    Eric

  12. Hi Eric and Ed,

    I’ve just verified that the script does work with wordpress 3.0. What happens when you echo DB_NAME? Does the php part reports any errors when executed manually?

  13. I know this a bit of a newbie question, but can you point me in the right direction of a resource that describes how you install a script onto your host.

    I host with media temple, and have about 25 websites running, all wordpress that I would like to be backed up automatically on a monthly basis.

    This sounds like the best solution, but I don’t really know where to start, any advice?

    cheers!

    Jaclyn

  14. You’ll need to copy the script and save it on your server, and then continue with the instruction in the post. If you’re having problems, please be more specific and tell which part is the problematic so I can be of better help.

  15. Where do I save it on my server? In the root directory or in the root of each website? I have many domains on the same server….

    If I am understanding correctly I can use 1 script to control the backups of all of the websites, so I would assume that if I placed the file above the other sites in the file structure then it could control them.

    Is there a particular file name I should use for the script, and can it be a regular .txt file?

    Thanks for you help!

    šŸ˜‰

    Jaclyn

  16. Preferably in the somewhere above all other sites (also it’s). Root directory is fine.

    The extension doesn’t matter as long it is executable. By conventions shell scripts like this have no extension or .sh extension. To make it executable see the part of the post regarding chmod.

  17. Hi Guy,

    I was running into an error similar to the one Eric and Ed were seeing. It turns out that my host’s standard php executable was probably the CGI version; it was displaying headers, so DB_NAME, etc., got mangled. My solution was to change “php” to “php -q” in all four lines:


    DB_NAME=`echo “<?php require_once(\"${BLOG_DIR}/wp-config.php\"); echo DB_NAME;" | php -q`
    DB_USER=`echo "<?php require_once(\"${BLOG_DIR}/wp-config.php\"); echo DB_USER;" | php -q`
    DB_PASS=`echo "<?php require_once(\"${BLOG_DIR}/wp-config.php\"); echo DB_PASSWORD;" | php -q`
    DB_HOST=`echo "<?php require_once(\"${BLOG_DIR}/wp-config.php\"); echo DB_HOST;" | php -q`

    Maybe this will help someone else as well?

    Thanks!

    Nate

  18. Thanks Guy.

    Had tried Nate’s suggestion to no avail.

    Moving to WP 3.01 resolved the issue for us.

  19. Guy,

    Is it possible to exclude certain directories during backup?

    One blog is on the web root but also has several non WP related directories with large files in them.

    Thank you.

  20. Hi Ed,

    I’m glad things sorted out for you. I wonder why it didn’t work for you and Eric in the first place.

    Regarding excluding certain directories, just add --exclude [dir name] to the tar tar line (it’s 2 lines below where it says “Creating tarball…”). There is already one exclude rule, which you can use as an example.

  21. Thank you Guy.

    I should have looked a little closer at the script code.

    Really appreciate your making this freely available.

  22. I’m having some issues getting this script to work…

    I’m getting a similar error as already mentioned, but the suggested fixes have no effect.

    dumping databaseā€¦ ./wp-backup: line 72: ${BACKUP_DIR}/${DUMP_NAME}: ambiguous redirect
    mysqldump: unknown option ā€˜–>ā€²
    failed!

    Any suggestions what might be causing this? Would the symbols in the password have any effect on this? The password contains a } and a comma… Then again, the previous version of this script worked perfect with the same DB details.

    Any help would be appreciated.

    Thanks!
    Andrei

  23. Nevermind – got this sorted out!

    Turns out one of the SuperCache files was stuck with paths from the old server, and this caused a warning to be echo’ed as well as the Constants.

    If anybody else is getting these ambigious redirects, try debugging the script by changing the first line to

    #!/bin/bash -x

    That’s how I discovered the source of my problem.

    Cheers!

  24. I know this is a stupid question. I am sure it is ridiculously simple.
    But I am new to this and am obviously missing something basic here.
    When you say “give the path to the blog as an argument” what do you mean? Which file? where in the file? I understand the line you wrote(at least what it does, but where does it go?

    Thanks!

  25. @Jim, when I wrote “give the path to the blog as an argument” it means that you need to put after the script name the path to the directory where the blog is installed on the server. The mentioned line should be executed from a shell on the server.

  26. I guess my question is even more basic. How do I execute the line mentioned from the shell? In a separate executable text file in the same directory? Is there somewhere else to write the line in the shell to execute? I am using webshell3 in Hsphere.

  27. Hi Jim,

    I’m not familiar with Hsphere. Basically, you should put the line directly in the shell.

  28. hey there – i posted on one of your previous post (original FTP backup script), not realizing that this one was the new one. i ran into one issue with the original script, which was that the command lftp (line 42) wasn’t recognized, so i wasn’t sure how to go about troubleshooting that — backup worked though. as to this updated script, i can’t seem to get it working because i can’t seem to figure out, for the life of me, how to give the path to the blog as an argument. my script is in the same directory (root) as my wp installation, so i’ve tried a bunch of combos to execute it and just can’t get it right. i’ve tried /var/www/vhosts/mysite.com/httpdocs/ and /httpdocs, just plain / and everything in between. i know you’re probably swamped with a ton of other things — and thank you for taking the time to actually post this! — but i was hoping you could point me in the right direction!

  29. 1. Install lftp using your package manager. Without it the local backups will work, but you won’t be able to preform the FTP backups.

    2. Have you looked at the example at the post (second code snippet)?

  30. Hi,
    Thanks for your script.
    I tested it on my local my machine and it was working, but one day I got the following error:
    ~/www$ sudo ./wp-backup wordpress/
    PHP Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 81 bytes) in /home/aser/www/wordpress/wp-includes/pomo/mo.php on line 204

    Any idea?
    Best regards

  31. I doubt that the error is related to the backup script, but I believe I may still be of help. Try to raise the memory limit available to your php. It can be done via the php.ini configuration file, and here should also be a programmatic way to change it.

  32. Hi,
    I had a 128mb limit in php.ini but I needed to change wp-settings also:
    define(‘WP_MEMORY_LIMIT’, ‘128M’);
    Nothing to do with your script šŸ˜‰

    Thanks

  33. Hi,

    Thx for this amazing script.
    I’ve a problem with FTP : my password is something like “blabla<1azd" and the "<" is a problem :

    ./wp-backup: line 17: Syntax error near to "1"
    ./wp-backup: line 17: `FTP_PASS=blabla<1azd'

    How to fix it please ?
    Thank again !

    StƩphane

  34. Hi StƩphane,

    Just surround it with quotes, e.g.:
    FTP_PASS="blabla<1azd"
    and it should do the trick

  35. Many thanks for the script… I will try and work out how to implement it… I looked at my hosting provider and it says that they have SSH Shell… I assume that this is where I should be working…

    Now what about the restore? is there another script to use?

    I am asking this becasue I want to test the whole process on a test website that I have before implementing it on the live one.

    Thank you…

  36. There is no script for restoring. In order to restore the backup you need to use an ftp client to fetch the tar archive and sql dump and then unpack the archive and import the dump to your db. If you need, I guess you can easily automate it.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.