Firefox Sync Server - Backup
Firefox Sync Server - Backup
- author
-
akeil
- date
-
2016-09-15
- version
-
1
This is a follow up on a previous post. where I installed a Firefox Sync Server on a Raspberry Pi running piCore. After having the Sync Service basically running, it is time to set up regular backups.
Filesystem Backup
This is a variant on a backup-scheme described in an older post. Most backups work by creating a backup locally and then pushing it to a remote server. In this case there is no remote server and the backup is to be stored on a desktop computer. The problem is that the desktop computer is not always running.
Therefore the backup will be initiated from the destination machine. It assumes that the source machine(s) will always be reachable.
TinyCore Linux already has a backup facility 1, namely filetool.sh
.
This creates a backup of selected files under mydata.tgz
.
Data is restored on every boot.
Use
$ filetool.sh -bs
The -s
option tells filetool to create a safe backup.
"Safe" means that the previous backup is secured before it is overwritten
with a new one.
Still, mydata.tgz
is stored in the tce
directory on a local drive.
And for a Raspberry Pi this means the SD card or an attached USB removable
drive. Not exactly reliable storage media.
We will use rsync 2 to periodically download data from the tce
directory
(and possibly other locations) to another computer.
The basic command should look like this:
$ rsync --archive rsync://box/<src> <dst>
Install and Configure rsync
Install rsync on the TinyCore Linux machine with:
$ tce-load -wi rsync
Install with -wi
to have it added to the onboot.lst
.
We need rsync to run in daemon mode so that the client can connect to it at any time.
First, create a minimal rsyncd configuration 3 at /etc/rsyncd.conf
:
uid = nobody gid = nogroup pid file = /var/run/rsyncd.pid log file = /var/log/rsyncd.log use chroot = no [tce] comment = tce directory backup path = /mnt/mmcblk0p2/tce read only = yes uid = tc
The config defines a module named tce
.
This means clients will see files under /mnt/mmcblk0p2/tce
when they request rsync://box/tce
.
Since it is only intended for backup it is marked as read only.
Add as many modules for other locations as required.
Note
Remember to add etc/rsyncd.conf
to /opt/.filetool.lst
.
Start it on boot in bootlocal.sh
:
# start rsyncd rsync --daemon
Stop it on shutdown in shutdown.sh
:
# stop rsyncd - location of pidfile from /etc/rsyncd.conf pid=$(cat /var/run/rsyncd.pid) if [ -n "$pid" ]; then kill "$pid" fi
The Backup Destination
The actual backup task runs on the computer which is the backup destination.
It will be set up so that it connects to a configured list of hosts (sources)
via rsync
.
The script retrieves a list of rsync modules from each host.
If a specific KEYWORD
(in this case: "backup") is part of the module
name or comment, all files from that module will be included in the backup.
The last KEEP
backups are kept, the oldest backup is removed.
Any host that is registered with the backup script can define any number
of rsync modules and if they contain the keyword, they will be backed up.
Hosts can also use the exclude
option in a module definition to control
which files are backed up.
On the destination this will result in a directory structure like this:
BASE/ foo/ # backups from the "foo" host files.0/ # the most recent backup of "files" [...] files.1/ # an older version of "files" [...] files.2/ [...] data.0/ [...] data.1/ [...] data.2/ [...] bar/ data.0/ data.1/
Where we have two hosts "foo" and "bar". The "foo" hosts has two rsync modules included in the backup and we have collected three backups of each (0..2). The "bar" host has only one module of which two backups were collected.
Systemd Timer and Service
To control the periodic backup through systemd
a .timer
and .service
file are needed.
The timer goes into /etc/systemd/system/pi-backup.timer
:
[Unit] Description=Timer for Rasperry Pi backup [Timer] OnCalendar=daily Persistent=true [Install] WantedBy=default.target
And the service in /etc/systemd/system/pi-backup.service
:
[Unit] Description=Backup for Raspberry Pis [Service] ExecStart=/usr/local/bin/pi-backup.sh
Assuming that the backup script is located at
/usr/local/bin/pi-backup.sh
.
The timer is activated with:
$ sudo systemctl enable pi-backup.timer
Backups can be started manually with:
$ sudo systemctl start pi-backup.service
Backup Script
The complete script looks like this. The UPPERCASE variables at the top of the script are meant for configuration:
#!/bin/sh # basedir for all backups ROOT=/path/to/backups # hosts to consider for backup HOSTS=( foo bar ) # modules with KEYWORD in name or description are backed up KEYWORD=backup # the number of old backups to keep (not including the current backup) KEEP=6 function main { for host in "${HOSTS[@]}"; do backup_host $host done } # fetch a list of modules # filter all modules with "backup" in their description # args: host function backup_host { local host=$1 # get a list of all modules for that host, # filter the ones containing "KEYWORD" # and keep only the module name rsync rsync://$host/ | grep "$KEYWORD" | cut -f1 | while read -r module; do backup_module $host $module done } # backup a single module # args: host module function backup_module { local host=$1 local module=$2 local basedst=$ROOT/$host/$module local dst=$basedst.0 local lndst=../$module.1 rotate $basedst echo Backup $host/$module to $dst mkdir -p $dst rsync --archive --delete --link-dest=$lndst rsync://$host/$module $dst } # drop the oldest backup, # move other backups up one place (e.g. `backup.0` to `backup.1`) # args: basedst function rotate { local counter=$KEEP local dst=$1 # going backwards: n, n-1, ... 0 while [ $counter -ge 0 ]; do ahead=$(($counter+1)) local current=$dst.$counter local older=$dst.$ahead if [ -d $current ]; then if [ $counter -eq $KEEP ]; then echo delete $current rm -r $current else echo move $current to $older mv $current $older fi fi counter=$(($counter-1)) done } # run it main
SQL Dumps
The Firefox sync server was installed using MariaDB as a database backend. We will perform logical backups of the database. That is, the backup takes the form of SQL statements which, when executed, restore the original data.
mysqldump 4 is used to dump the complete database into SQL statements.
The backup script for the ffsync database looks like this:
#!/bin/sh dst=/mnt/storage/mysql/dumps/ffsync.dump cfg=/opt/ffsync.db.cnf mysqldump --defaults-extra-file=$cfg --lock-tables ffsync > $dst.temp status=$? if [ $status -eq 0 ]; then mv $dst.temp $dst fi exit $status
The --lock-tables
option ensures that we retrieve a consistent
state of the database.
For InnoDB table types, --single-transaction
is recommended to achieve that
but table locking will work with any storage engine.
To avoid having the database password in the command line,
a configuration file is used to keep credentials.
It is passed with --defaults-extra-file
.
The config file looks like this:
[mysqldump] user=ffsync password=<secret>
Set the permissions for the config file so that only the owner can read it
and make it owned by the mysql
user.
$ sudo chown mysql:nogroup /opt/ffsync.db.cnf $ sudo chmod 600 /opt/ffsync.db.cnf
Both, script and config file are kept in /opt
which means they
should already be included in filetool.lst
for backup and restore.
Finally, add the script to mysql's crontab:
$ sudo crontab -eu mysql
12 1 * * * /opt/backup-ffsync-db.sh
The backup will be executed with the user we created to run the mysqld
service (mysql
) so make sure that the backup destination is writable
for that user.
To include the SQL dump in the filesystem backup,
create an rsync module for it in rsyncd.conf
:
... [sqldumps] comment = SQL dumps backup path = /mnt/storage/mysql/dumps read only = yes uid = mysql
Cron
We have made a crontab
entry but cron might not be enabled.
To enable it, we must add the Tiny Core bootcode 5 "cron
".
Bootcodes can be set in a file named cmdline.txt
.
the file is located in the boot partition, which is normally
unmounted after boot. Mount it and edit the file:
$ sudo mount /dev/mmcblk0p1 /mnt/mmcblk0p1 $ sudo vi /mnt/mmcblk0p1/cmdline.txt (append bootcode "cron") $ sudo umount /mnt/mmcblk0p1
cmdline.txt contains a space separated list. Simply append " cron" to the end of that list.
Warning
With piCore 8.x and Raspberry Pi 3,
the file is cmdline3.txt
, not cmdline.txt
.
See http://forum.tinycorelinux.net/index.php?topic=20107.0
After a reboot, check if it worked.
This should return the PID of the running crond
daemon:
$ pgrep crond
Now make sure that crontabs are persisted across boots.
Add the crontabs directory to /opt/.filetool.lst
:
var/spool/cron/crontabs
Timezone
If you did not set it, piCore's time zone is UTC. And your crontab entry would refer to UTC as well.
This is a good opportunity to add another bootcode (tz
)
for setting the timezone.
The TZ bootcode 6 is a bit more involved it (not as complicated as it looks, though). For Central European Time the timezone is encoded like this:
tz=CET-1CEST,M3.5.0,M10.5.0/3 | | | || | | || | | `- 03:00:00 | | | || | | || | `--- Sunday (day 0) | | | || | | || `----- Last week (week 5) | | | || | | |`-------- October (month 10) | | | || | | `--------- End of DST in format m.w.d[/h] | | | || | `----------- Sunday (day 0) | | | || `------------- Last week (week 5) | | | |`--------------- March (month 3) | | | `---------------- Begin of DST in format m.w.d[/h] | | `--------------------- TZ name during DST | `----------------------- UTC offset w/o DST `-------------------------- TZ name w/o DST
Start and end times for DST are specified in the format:
Mm.w.d[/h] ^ ^ ^ ^ m: month, 1=January w: week of the month (1=first, 5=last) d: day of the week, 0=Sunday, 6=Monday h: [optional] hour of the day, 3 for 03:00:00
If no time parameter is given for DST start or end time, 02:00:00 is assumed.
Add the parameter to cmdline[3].txt
(for CET):
tz=CET-1CEST,M3.5.0,M10.5.0/3
Whether setting the timezone this way (or setting it at all) is a good idea is debatable. For me - living in a country with daylight savings time - it felt more comfortable having the same time on all computers.