To archive personal data I use Unison over SSH to copy the data to a remote server.

Install unison

dnf install make ocaml
cd repos/third-party
git clone https://github.com/bcpierce00/unison.git
git checkout v2.51.4
cd unison/src/
make UISTYLE=text

Note that not only should unison need to be the same version on all hosts, but also the version of ocaml it builds against.

Then I symlinked src/unison to ~/.local/bin/unison, which is included in my PATH.

Note that the version of ocaml used to build unison needs to be the same. For example, to match the version of ocaml in Debian Bullseye on my old 32-bit i386 server I had to build unison on my laptop as follows:

podman pull fedora:34
cd unison
podman run -it -v "${PWD}:/mnt:Z" fedora:34
dnf install make ocaml
cd /mnt/src
make UISTYLE=text

Systemd user timer

Add the following templated Systemd timer (i.e. [email protected]) and it’s corresponding service (i.e. [email protected]) under ~/.config/systemd/user, while making sure to update the path to the unison executable:

[Unit]
Description=Synchronize ~%f to the remote server

[Service]
Type=oneshot
ExecStart=/home/user/.local/bin/unison -auto -batch -times -xattrs \
                                       /home/user%f \
                                       ssh://remote-server//home/user%f
[Unit]
Description=Synchronize ~%f to the remote server

[Timer]
OnBootSec=10m
OnUnitActiveSec=10m

[Install]
WantedBy=timers.target

I enabled archiving of a directory named ‘doc’ in my home directory as follows:

systemctl --user enable [email protected]
systemctl --user start [email protected]

If you would like to use a path containing a / then systemd-escape will need to be used to create the timer:

systemd-escape [email protected] 'path/to/directory'

Then check that the timer ran:

systemctl --user list-timers --all

Distributed synchronization

Although the above approach provides redundant backups across many hosts it depends on a single host as the source of truth. This can become problematic if that host goes down. When trying to synchronize directly in a mesh topology the hostname of the remote-server cannot be hardcoded in the service file.

Instead, I create a profile file in ~/.unison/ for each connection. For example, the above command was replaced by ~/.unison/remote-server-home-user-doc.prf:

root = /home/user/doc
root = ssh://remote-server//home/user/doc

auto = true
batch = true
times = true
xattrs = true

References