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.
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…
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!
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?
This is not an incremental backup, as each little change requires duplicity to perform a full backup of the whole dump.