Incremental WordPress Backups using Duply (Duplicity)

This post outlines how to create encrypted incremental backups for WordPress using duplicity and duply. The general method, as you will see is pretty generic, and I’ve been using it successfully to backup also Django sites and MediaWiki installations. You can use this method to make secure backups to almost any kind of service imagineable: ftp, sftp, Amazon S3, rsync, Rackspace Open Cloud, Ubuntu One, Google Drive and whatever else you can think about (as long as the duplicity folks implemented :-)). If you prefer a simpler solution, and don’t care about incremental or encrypted backups, see my Improved FTP Backup for WordPress or my WordPress Backup to Amazon S3 Script.

Duplicity is the magic behind all this. It’s a handy program that manages the actual backup process. It creates the incremental diffs, encrypts and saves everything to the remote server. The downside of duplicity is its lack of permanent “configuration” – each time you need to specify every detail about the backup job. Duply, a wrapper around duplicity, sovles this by creating a configuration file to each backup job.

I’ll describe using both to make encrypted incremental backups for both the files and the database (assuming mysql). If you’re using another database, like PostgreSQL, you could probably do something similar. We start by initializing a duply configuration for our new backup job:

$ duply my_blog create

This will create a duply profile directory ~/.duply/my_blog/. Unless otherwise noted, we will refer to files in that directory.

The next step is to edit the variables defined in conf file to suit your needs. The file is fairly documented, so it shouldn’t be a problem. I’ll walk you through the major things that need your attention and modifications.

The first thing which you will want to set is SOURCE to where your blog resided (e.g. /home/user/my_blog. We’ll also drop the sqldump of the database there, but more on that later.

TARGET determines where the backups will go to. Almost anything that comes to mind is supported: FTP, SFTP, SSH, Amazon S3 (my favorite), Ubuntu One, Cloud Files, loc files and even mail (and I haven’t listed everything). You should see Duplicity’s documentation on URL format for details on exactly how to specify it, as it is backend dependent. Some examples are:

file:///home/user/backups
ftp://example.com/backups
s3://s3.amazonaws.com/my_bucket/backup_dir

You should use TARGET_USER and TARGET_PASS to specify the username and password for authenticating the backend if necessary (if you are using S3 it will be your AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY respectively).

MAX_FULLBKP_AGE specifies how often should a full backup be preformed instead of incremental ones. Time format can be specified using values like 1Y, 3M etc.

You’ll want to set MAX_AGE and MAX_FULL_BACKUPS as this help you remove old incremental and full backups as they expire.

Last but not least, the GPG_PW and GPG_KEY are used to specify encryption passphrase and keys. If you don’t specify a GPG_KEY, the passphrase will be used for symmetric encryption. If you do specify, asymmetric encryption will be used. The config file duply created will have further information on more advanced configurations (like encrypting and signing with different keys, or encrypting but no signing so no private key is needed).

The next thing to edit is the exclude file and add patterns for files to ignore. If you use wp-cache or WP Super Cache you should do the following:

$ echo "**cache" >> ~/.duply/my_blog/conf

Until now we handled the backup of files, and nothing was WordPress specific. Save the next snippet under ~/.duply/my_blog/pre (taken from my Improved FTP Backup for WordPress script):

#! /bin/bash

umask 077

# Uncomment for duply >=: 1.5.4.2
# if [ "${CMD_NEXT}"  != "bkp" ]; then
#   echo "Skipping, not running a backup"
#   exit 0
# fi


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

mysqldump --user="${DB_USER}" --password="${DB_PASS}" --host="${DB_HOST}" \
 --databases "${DB_NAME}" > "${SOURCE}"/dump.sql

The is will cause the script above to run before each backup. The script reads wp-config.php and dumps the blog’s db into a file called dump.sql in root directory of the blog. Now in order prevent accessing the dump file, black list it in the web server. If you use Apache, add the following to your htaccess

<files dump.sql="">
Deny
</files>

If you use lighttpd, you can use mod_access to do the same:

url.access-deny            = ( "~", ".inc", ".sql" )

(this will block everything that ends with “.sql“, change this if it doesn’t suit you).

Finally to the backup itself.

$ duply my_blog backup
$ duply my_blog restore 

The first will backup everything as you configured, making incremental and full backups as needed. The second restores the files to their original location. After restoring, you’ll need to manually import the dump.sql file. See duplicity and duply documentation on how to restore to other location, restore only specific files, etc.

6 thoughts on “Incremental WordPress Backups using Duply (Duplicity)”

  1. backupninja linux cli solves the problem in 5 minutes, many backends and support duplicity (also mega.co.nz) , mysql backup, no need to write script…

  2. The DB backup script you provided didn’t work with HHVM — I don’t have standard PHP, so I don’t know if it’s a PHP/HHVM difference or a change in WordPress’s wp-config.php file. echo statements after the require_once command don’t produce any output.

    I extracted the DB settings from wp-config.php to a new file (wp-db-settings.php), and added a line in wp-config.php:
    require-once(‘wp-db-settings.php’);
    and removed the four settings from being declared in wp-config.php.

    I then updated the script to include wp-db-settings.php instead, and everything worked great!

  3. What is the proper way to backup onto ones desktop drive, or any storage volume, our websites under construction or the published version, ideally in an ongoing way per increments, (each time any data is added), or daily or weekly backups, whatever is preferred?

  4. This is not an incremental backup, as each little change requires duplicity to perform a full backup of the whole dump.

Leave a Reply

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