I maintain several Ubuntu systems and needed a simple bash script that would backup / mirror these machines. Google pointed me to rsync. This article describes what I did with it.

Synopsis

remote_mirror is a bash function that calls rsync under the hood. For example, the following mirrors 192.168.1.102:/etc into /backup/mirror/192.168.1.102/etc.

remote_mirror 192.168.1.102 /etc

Here is its output:

mirror@dl-desktop:~$ remote_mirror 192.168.1.102 /etc
[2025-02-15 13:28:57] [remote_mirror] 192.168.1.102 /etc
[2025-02-15 13:28:57] [rsync] receiving incremental file list
[2025-02-15 13:28:57] [rsync] etc/openvpn/openvpn-status.log
[2025-02-15 13:28:58] [rsync] 
[2025-02-15 13:28:58] [rsync] sent 511 bytes  received 157,592 bytes  105,402.00 bytes/sec
[2025-02-15 13:28:58] [rsync] total size is 14,464,271  speedup is 91.49

Below, note that we require sudo, as find alone would emit “Permission denied” warnings.

mirror@dl-desktop:~$ sudo find /backup/mirror/192.168.1.102/etc -type d | sort
/backup/mirror/192.168.1.102/etc
/backup/mirror/192.168.1.102/etc/acpi
/backup/mirror/192.168.1.102/etc/acpi/events
/backup/mirror/192.168.1.102/etc/alternatives
...

Calls to remote_mirror, and its local equivalent local_mirror, are collected in a batch script which is called by cron once a day. This happens on a local machine where /backup is mounted to an external hard drive.

Preparations

The crux of our problem is multifold:

  • the process must preserve file and directory ownership;
  • it must be exhaustive and complete with respect to file and directory permissions;
  • it cannot require manual entry of passwords;
  • it takes place in a secure way

To handle this, we create a mirror user account on each machine. Anticipating ssh, we use ssh-copy-id so that the local mirror user may access remote mirror accounts without need for a password.

To read/write files with arbitrary owners and permissions will require privilege escalation. The simplest way forward is to work with sudoers. Specifically, we allow all mirror accounts to run /usr/bin/rsync with the NOPASSWD modifier. This takes the following form – use visudo:

mirror ALL=(ALL) NOPASSWD: /usr/bin/rsync

rsync parameters

Running as local mirror, the rsync call associated with the example looks like this:

sudo \
    rsync -av \
    -e "sudo -u mirror ssh" \
    --relative \
    --delete \
    --rsync-path="sudo rsync -a" \
    192.168.1.102:/etc /backup/mirror/192.168.1.102

Breaking this down:

The initial sudo ensures that we can write files with arbitrary ownership and permissions.

The -e "sudo -u mirror ssh" specifies a remote shell spawned by local mirror which will be able to ssh without a passowrd.

--relative will preserve the full source pathd. Without it, remote_mirror 192.168.1.102 /var/lib would get mapped to /backup/mirror/192.168.1.102/lib.

--delete imposes mirror-like sematics.

--rsync-path="sudo rsync -a" ensures that we can read files with arbitrary ownership and permissions.

loggable

We provide logger and timestamp functions to faciliate logging.

Easy rsync for Local and Remote Backup