Backup FreeBSD Jails Using Ezjail

Using jail to separate individual running services is very easy to achieve in FreeBSD. In my case, I put my several websites into different jails just for easy maintenance and a clear mind. With the jails set up, it is then becomes the most important job to enable a stable backup plan for all the jails.

In this article, I will introduce my way of backing up jails using ezjail, rsync, and crontab.

Archiving Jails Using Ezjail

ezjail provides a very easy-to-use command to create a archive tarball of any given jail: ezjail-admin archive. For example, if you have one jail called www.example.com, you can create a jail by

sudo ezjail-admin archive www.example.com

The default location for the archive is at /usr/jails/ezjail_archives. You will find some file like this after you’ve run the command: www.example.com-201511060904.36.tar.gz.

Note that, ezjail does not allow you to create an archive of a running jail. I saw some articles saying you can do that, but in my experience, it never works. So that means you need to stop the jail, do the archive, and start the jail again. After reading through the manpage of ezjail-admin, I found that you can use the option -f to allow the backup to take place without stopping the jail. However, it is not recommended in practice.

If you put stopping, archiving, and starting in one script, it will look like:

ezjail-admin stop www.example.com
ezjail-admin archive www.example.com
ezjail-admin start www.example.com

Tip: You can find all running jails using the command jls.

Copying Backups to Remote Server

There are many ways to back up your archives to a remote server, such as scp, rsync, ftp, etc. However, in my case, I find using rsync is the simplest way to do this.

rsync is a remote synchronization tool that can let you easily synchronize the content of two folders. As we mentioned before, all the archived ezjail backups are stored in one folder. In this case, the most easy way to sychronize the backups to remote servers is to use rsync.

Here is a example command that can do so:

rsync -avz --delete /usr/jails/ezjail_archives USER@SERVER:BACKUPFOLDER

The -a means keep the permission, -v shows the progress, and -z allows rsync to compress the data before sending to the remote server.

Periodically Run the Backup Procedure

The last step toward a automatic backup procedure is to configure cron jobs. In FreeBSD, all the default cron jobs are located at /etc/periodic/*. For exmaple, all the daily running jobs are in /etc/periodic/daily.

I created a file 220-jail-backup in the daily folder and put the following code in it:

/etc/periodic/daily/220-jail-backup:

#!/bin/sh

cd /usr/jails/ezjail_archives/

ls -1tr nginx*.gz | tail -n +6| xargs rm -f
ezjail-admin stop nginx
ezjail-admin archive nginx
ezjail-admin start nginx

ls -1tr blog*.gz | tail -n +6| xargs rm -f
ezjail-admin stop blog
ezjail-admin archive blog
ezjail-admin start blog

ls -1tr frontpage*.gz | tail -n +6| xargs rm -f
ezjail-admin stop frontpage
ezjail-admin archive frontpage
ezjail-admin start frontpage

su - mingwei -c "rsync -avz --delete /usr/jails/ezjail_archives USER@SERVER:BACKUPFOLDER"

Important note: crontab by default does not have the path for ezjail, and we need to manually add that path to the crontab configuration. Add the path /usr/local/bin to the /etc/crontab file’s PATH variable should do the trick. The config will be something like this:

/etc/crontab:

# /etc/crontab - root's crontab for FreeBSD
#
# $FreeBSD: releng/10.2/etc/crontab 194170 2009-06-14 06:37:19Z brian $
#
SHELL=/bin/sh
PATH=/etc:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin
#
#minute hour    mday    month   wday    who     command
#
*/5     *       *       *       *       root    /usr/libexec/atrun
#
# Save some entropy so that /dev/random can re-seed on boot.
*/11    *       *       *       *       operator /usr/libexec/save-entropy
#
# Rotate log files every hour, if necessary.
0       *       *       *       *       root    newsyslog
#
# Perform daily/weekly/monthly maintenance.
1       3       *       *       *       root    periodic daily
15      4       *       *       6       root    periodic weekly
30      5       1       *       *       root    periodic monthly
#
# Adjust the time zone if the CMOS clock keeps local time, as opposed to
# UTC time.  See adjkerntz(8) for details.
1,31    0-5     *       *       *       root    adjkerntz -a

Enjoy!