My Web Server/Drupal installation backup strategy with backupninja

Printer-friendly versionPDF version

So in this article I'll show you an example of backup that I employ for my server. I have been using a manual approach for a long time (which I'll hint at towards the end) but now I have switched in favor of an automated option. You will see that on my odroid u2 server, I have attached a usb stick. This is where my backups are created.

When you are done followning this guide, you will not just back up your important data but you will also do be doing an integrity check using "aide" of your system, with a published integrity report for each backup against the last taken backup. I explained about using aide here previously. You can have a read there about basic usuage and intent.

The tool for back up that I setup is called backup ninja. I didn't use rsync, I favored complete discrete weekly backups using tar. So lets deep dive and see how I setup things.

So first thing first install backupninja. For debian its as simple as:

apt-get install backupninja

After this there will be a directory created "/etc/backup.d". We will be placing files into this directory that will direct backupninja about what to do. All files here *must* be owned and readable only by root otherwise backup ninja will complain and abort. One probable reason why only root should have access to these files that I noted might be that I noticed that the mysql password needs to be stored in the backup action file in clear text. So now in the following sections we will configure different files that go in this location. These files will represent actions to backupninja. And these actions are executed based on name prefix which are numerals. So the lowest numbered actions goes first and than the next higher one and so on. You'll understand more on that as we progress.

Step 1: Backup Initilization script

To get things going, we need to do some initialization. For this create a bash script file called "" under "/etc/backup.d". Make the file executable and than you can add the following contents:

#first do actions as root user
umount /dev/sda1
mount /dev/sda1 $MEDIA_MOUNT_POINT

#If a previous failed backup exists, move it to another dated folder(date is form time of running of this script and not failed backup)
if [ -d "$MEDIA_MOUNT_POINT/fresh-dir" ]; then
  # Control will enter here if $DIRECTORY exists.
  mv $MEDIA_MOUNT_POINT/fresh-dir $MEDIA_MOUNT_POINT/fresh-dir-$(date +%F--%T)
mkdir -p $MEDIA_MOUNT_POINT/fresh-dir/aide

# Backup the list of your software selections.
dpkg --get-selections > $MEDIA_MOUNT_POINT/fresh-dir/installed-software.log

# The next lines are drupal specific
cd /home/webuser/public_html/ahsanscorner
drush cc all
drush bam-backup

So what did we do in this script. Well I have folder called "/media/backups". I mount the usb stick at this location. The next line deletes a folder "fresh-dir". This folder will be non-existent but in case there is one, we delete it. Than we recreate this folder plus another one to hold the "aide" database.

The next line backups all your installed software selection list. You can use this list to reinstall all your software in case you need to, on a fresh system.

The last 3 lines are drupal specific. You need the "back_migrate" module from drupal for this to work and you need drush to be configured for the root user. This is a redundant backup of the drupal database from my side. But I wanted this redundancy just in case the sqldump file was not correct or something. You can remove this if you want to while we are going to create a mysql backup option in backupninja as well later on.


Step 2:Files backup

Now lets now move on to backup of important files. We are going to use a little helper utility from the terminal called "ninjahelper". As root run it and choose "new" from the choice list that appears and do the below :

Backupninja new backup action screen

  • From the new backup action screen choose: "tar backup" option.
  • In the next screen "When to run this action" screen, delete whatever value you have there. We will configure cron later on for when to run complete backupninja
  • Provide a name for the backup in next screen.
  • Provide location of backup in the next screen. Note if you are following my strategy than give "/media/backups/backup-ninja-dir" as the location here.
  • Provide compression strategy in next screen. I choose bzip.
  • Than in the next screen just start providing all the important locations and files you want backed up. Don't worry if you forget something here or can't think of everything at first go. You can come back and add file here manually or just edit the config file later on in a text editor that gets created under "/etc/backup.d".
  • The next screen is the exclude screen. I left everything here alone. Additionally you can also provide exceptions here, for e.g. I backup my home directory, but the odroid base image that I am hosting is 600MB or so and don't I want it backed up everytime. So exclude such things here.
  • Press enter and you are back again on the new action screen. This makes is into /etc/backup.d/20.tar file (which is not actually a tar file but a text file).

If you are using my customized odroid u2 debian image, these locations are definitely needed with anything else you put in there, below is what the file looks like for me on my odroid arm system. You can always manually modify this file at any point in time.


#when = 
backupname =
backupdir = /media/backups/fresh-dir
compress = bzip 
includes =  /etc/geodb /etc/webmin /etc/php5 /etc/default/memcached  /home/ /root /etc/backup.d /etc/apache2 /etc/init.d/x11vnc /etc/shorewall /etc/aide /etc/modsecurity /etc/monitorix /etc/fail2ban /etc/hostname /etc/hosts /etc/hosts.allow /etc/hosts.deny /var/lib/aide
excludes =  /var/lib/aide/aide.db /var/lib/aide/ /*.Xauthority /*.recently-used* /*.local/share/Trash /*.pulse* /*.gimp-2.8 /home/*/.gksu.lock /*.goutputstream* /*.xsession-errors* /*.dbus /*.cache /*.gvfs /*.local/share/gvfs-metadata /*.thumbnails  /tmp /proc /sys /dev /srv /media /misc /net /selinux /home/webuser/*/2015.02.27-DebianWheezyWebHostingBaseImage.img_.7z /home/webuser/public_html/*  /*.mozilla/firefox/*/Cache /*.mozilla/firefox/*/minidumps /*.mozilla/firefox/*/.parentlock /*.mozilla/firefox/*/urlclassifier3.sqlite /*.mozilla/firefox/*/blocklist.xml /*.mozilla/firefox/*/extensions.sqlite /*.mozilla/firefox/*/extensions.sqlite-journal /*.mozilla/firefox/*/extensions.rdf /*.mozilla/firefox/*/extensions.ini /*.mozilla/firefox/*/extensions.cache /*.mozilla/firefox/*/XUL.mfasl /*.mozilla/firefox/*/XPC.mfasl /*.mozilla/firefox/*/xpti.dat /*.mozilla/firefox/*/compreg.dat
# tar binary - have to be GNU tar
#TAR=/bin/tar --verbose
#DATE           /bin/date
#DATEFORMAT     "%Y.%m.%d-%H%M"

Space saving tip

  • Above is a modified version of tar backup than I originally published. I halfed the size of my zip backup via the above excluding various directories in home folder that can be safely excluded.
  • Another space saver was the GeoCityLite.dat database that my drupal blog needs. Various plugins wanted it in different locations. At first I had it every where, than I moved it to "/etc/geodb" and softlinked it for every module requiring it.
  • Also some cached files for drupal that can be re-generated on recovery.


Step 3:MySql backup

If you closed ninja helper, you need to start it up again. Than do create new action again and from the new action screen start doing the following steps :

  • Choose mysql option in the new action screen above.
  • Than simply provide the desired backup directory location in next screen. For this article sake assume it to be "/root/backup-ninja-dir". We will use this later.
  • The next screens ask you whether you want to save all databases or individuals databases. Choose what ever option suits you.
  • In the next screen I choose the "password" option. Again feel free to experiment if you want to.
  • Moving on to the next screen you will be asked for individual mysql users and their passwords. Provide those to backupninja. And press ok.
  • Next screen is about the mode of sql backup. I choose the below options.

SQL dump option in backup ninja

  • This will bring you back to the "new backup actions screen", with an entry created for the mysql backup action you just created right now.
  • Note the the location of configuration file as /etc/backup.d/30-mysql.


Step 4: AIDE (Advanced Intrusion Detection Environment) setup

There is a cron file for aide that can be found at "/etc/cron.daily". You can disable this cron job by removing the execute flag on this file. As a next step lets go to the file "/etc/aide/aide.conf" and make sure the 2 properties below are same for you as me or make note of these:


Now create another script file under "/etc/backup.d", lets call it "". Copy the contents from the below section as below:

# umount so that the integrity check ignores the device.
umount /dev/sda1
rm /var/lib/aide/ /var/lib/aide/aide.db
aide --config /var/lib/aide/aide.conf.autogenerated --init
mount /dev/sda1 $MEDIA_MOUNT_POINT
mv /var/lib/aide/ /media/backups/fresh-dir/aide/
LAST_BACKUP_DIR=`ls -lrt | grep backup | awk '{print $9}' | tail -1`
if [ -d "$LAST_BACKUP_DIR" ]; then
	# Control will enter here if $DIRECTORY exists.
	cat &lt;<eot> $MEDIA_MOUNT_POINT/fresh-dir/aide/aide-compare.conf
        # This is too heavy for odroid u2 and results in server instability, so disable for u2, for normal servers you can keep this on.
	#aide --compare --config=$MEDIA_MOUNT_POINT/fresh-dir/aide/aide-compare.conf &amp;&gt;  $MEDIA_MOUNT_POINT/fresh-dir/intrusion-report.log

What the above script does is as follows, we un mount our backup media, as we don't want it part of the integrity check. Than we start the initialization of the aide database. Once that completes we remount the usb media back and copy over the resulting database to the media. Than we initiate the compare of the aide databases from the previous backup directory with the current backup directory. The result of this comparison we store in the main backup folder as the file "intrusion-report.log." The "fresh-dir" above is just a name to simplify the calculation of the last backup directory to use. Also no comparison takes place if backup is for the first time.

A point to note is after some many failed backups, I realized the "aide compare" operation on arm is just too much for the poor thing. I had to disable this for backups to go through.


Step 5: Finalizaton script


This is my very last script, I called it "". Again owned by root and executable by root. You can put any cleanup action you think you need as a the last step here.

rm -rf /home/webuser/private-file-repos/backup_migrate/

backup_folder_name=$(date +%F--%T)
mv $MEDIA_MOUNT_POINT/backup-ninja-dir $MEDIA_MOUNT_POINT/${backup_folder_name}-backup
umount /dev/sda1

This just deletes the backup_migrate folder that the drupal "backup_migrate" module creates for me. This is in the private file repository for drupal, if you have configured one. If you don't cleanup this directory every time you invoke the backup and migrate module, it creates a date based folder at that location. Our tar action just needs the last one created, every time we backup. So everytime that you backup, if you delete this folder, the next time you backup , you will only have only one folder; from your very last backup.

Scheduling backupninja to run

This was the most unbelievable part for me. There was a cron job at location "/etc/cron.d/backupninja". I edit it to say something like below so that it runs

# run backupninja every Sunday at 3 AM
00 3 * * Sun root if [ -x /usr/sbin/backupninja ]; then /usr/sbin/backupninja; fi

Since the weekend is the last productive day for my blog, I wanted the backup to run at 3:00 AM every Sunday night. I left this setting on for a few weeks. But there was not backup happening for some reason. Upon investigation, the log files seemed to be saying something in the lines of "Not starting current action because current time does not matche Sunday at 15:00)". I guessed than that the "when" option that backupninja needs found globally in "/etc/backupninja.conf" needs to match the time that the cron job starts backup ninja. Went there changed when to read something like "when = Sun at 3:00" and sure enough backups started happening.

The when option can be provided on each backup action configuration file, but the documentation says they should be the first line of each of these files. Also if you want an action to run one after another than, the later one starting, when the previous action finsihes, that the when part should provide the same time. Than backup ninja takes care of this.

By default the backup ninja cron job wakes up every hour. I changed that since it was an overkill in my case. Weekly backups for me were just fine. If you have various backup actions running at different part of the days, feel free to keep this value as it or change it.


A manual option

 It is a manual strategy, whereby after a few articles, I say ok its time to backup manually now. Than from my main desktop machine running linux, I have a script which logs onto my web server via ssh. Executes the backup actions we are going to configure below; consolidats all backup in a single location. Than I just secure copy "scp" the files to my desktop machine as backups. This is how the script on my desktop looks like :

backup_folder_name=./myDrupalSite-backup/$(date +%F--%T)
mkdir -p $backup_folder_name
echo "Executing backup -now ..."
ssh root@$remote_host 'backupninja -n'
wait $!
scp -r root@$remote_host:/root/backup-ninja-dir $backup_folder_name

The above will create a timestamp folder and also the "myDrupalSite-backup" in current directory if you are running this for the first time. Than it will run the remote command "backupninja -n" on the remote server. This will cause all configured backup actions on your serve to be executed. We will get to this part in a bit. Finally it will secure copy the backups consolidated at a pre-determined location by the backup actions and copy them over to this machine. Make note this has to be run by root user via ssh. I disabled ssh for root user for security users and it became no longer a viable option for me.


So enjoy configuring your system for back ups and integrity checks.


Add new comment