Automated encrypted incremental backups with restic to a Synology mount
Synology
The Synology devices are easy to setup but the backup applications are not that great. In addition, Synology does not offer SSH key based authentication for non-privileged accounts out of the box. After each upgrade the SSH key setup might be gone and it always feels like a hack.
The following text describes how to setup painless, automated, encrypted, incremental backups via CIFS using Restic.
The script makes use of passwords stored in the gnome keyring and thus can mount a CIFS aka Samba share without having to store the Synology user password
in the /etc/fstab
file or in the clear in a local file.
Restic
To quote the restic web site
restic is a program that does backups right. The design goals are: Easy: Doing backups should be a frictionless process, otherwise you are tempted to skip it. Restic should be easy to configure and use, so that in the unlikely event of a data loss you can just restore it. Likewise, restoring data should not be complicated. Fast: Backing up your data with restic should only be limited by your network or hard disk bandwidth so that you can backup your files every day. Nobody does backups if it takes too much time. Restoring backups should only transfer data that is needed for the files that are to be restored, so that this process is also fast. Verifiable: Much more important than backup is restore, so restic enables you to easily verify that all data can be restored. Secure: Restic uses cryptography to guarantee confidentiality and integrity of your data. The location where the backup data is stored is assumed to be an untrusted environment (e.g. a shared space where others like system administrators are able to access your backups). Restic is built to secure your data against such attackers, by encrypting it with AES-256 in counter mode and authenticating it using Poly1305-AES. Efficient: With the growth of data, additional snapshots should only take the storage of the actual increment. Even more, duplicate data should be de-duplicated before it is actually written to the storage backend to save precious backup space. Free: restic is free software and licensed under the BSD 2-Clause License and actively developed on GitHub.
The pre-requisits
We need the following things beforewe can start the backup:
- A Synology user account
- Restic installed on the local machine
- The username and password stored in the Gnome keyring using the secret-tool
- An initialized restic repository
- The repository password stored in the Gnome key ring
The prerequisits are rather easy to setup. We need to add the username and password once to the Gnome keyring. We can use a label and some attributes. The attributes are used for finding the username and password again in the key ring.
secret-tool store --label="Synology username" synology username
Our user should also be able to mount the remote folder. One wayt to achieve this is by allowing the user to use sudo without a password for the mount and unmount command. This can be done by adding the following line to the sudoers file:
stefan ALL=(ALL) NOPASSWD: /usr/bin/mount, /usr/bin/umount, /usr/bin/mkdir, /usr/bin/chown
The restic commands are pretty self explainatory.
restic -r ${SYNOLOGY_BACKUP_PATH} backup \
~/git \
~/.aliases \
~/.zshrc \
~/.bashrc \
~/.vimrc \
~/.ssh
In order to be mindfiul about the used storage, we will prune snapshots after a while.
# Prune older snapshots but keep 2 pe day, 7 days and 4 weeks
restic -r ${SYNOLOGY_BACKUP_PATH} \
forget \
--prune \
--keep-hourly 2 \
--keep-daily 7 \
--keep-weekly 4
The automation part is done by a classic cron job which runs for instance every 4 hours.
The prerequisits are described in the comments of the script below.
The backup script
The following script will backup the folders and files listed in the backup command.
#!/usr/bin/env bash
# exit when any command fails
set -e
# The following script assumes that you initialized the directory $SYNOLOGY_BACKUP_PATH
# on the Synology as a new restic repository:
# restic -r ${SYNOLOGY_BACKUP_PATH} init
# Make sure to add the username and the password first to the key ring
# secret-tool store --label="Synology username" synology username
# secret-tool store --label="Synology password" synology password
# Also add the restic password to the keyring
# secret-tool store --label="Restic password" restic password
# Add the mount and umount command without sudo password
# by using sudo visudo and add this line (adapt username)
# sproell ALL=(ALL) NOPASSWD: /usr/bin/mount, /usr/bin/umount, /usr/bin/mkdir, /usr/bin/chown
# Add a cron job which runs every 4 hours (for example)
# MAILTO="stefan.proell@cropster.com"
# 0 */4 * * * DISPLAY=:0 /home/sproell/scripts/automatic-restic-backup.sh
NAS_IP=192.168.1.10
BACKUP_MOUNT_TARGET=/media/${USER}/cropster-synology-backup
SYNOLOGY_PATH=/home
SYNOLOGY_BACKUP_PATH="${BACKUP_MOUNT_TARGET}/2020-restic-backups"
LOCAL_USER_ID=$( id -u )
LOCAL_GROUP_ID=$( id -g )
isPathMounted() { findmnt -rno TARGET "$1" >/dev/null;}
runResticBackup()
{
# Store the repository password in the environment variable
RESTIC_PASSWORD=$( secret-tool lookup restic password )
export RESTIC_PASSWORD
# Check of the remote directory exists, otherwise create it
[ -d ${SYNOLOGY_BACKUP_PATH} ] || ( \
sudo mkdir ${SYNOLOGY_BACKUP_PATH};\
sudo chown -R ${LOCAL_USER_ID}:${LOCAL_GROUP_ID} \
${SYNOLOGY_BACKUP_PATH})
restic -r ${SYNOLOGY_BACKUP_PATH} snapshots
restic -r ${SYNOLOGY_BACKUP_PATH} backup \
~/git \
~/.aliases \
~/.zshrc \
~/.bashrc \
~/.vimrc \
~/.ssh
# Prune older snapshots but keep 2 pe day, 7 days and 4 weeks
restic -r ${SYNOLOGY_BACKUP_PATH} \
forget \
--prune \
--keep-hourly 2 \
--keep-daily 7 \
--keep-weekly 4
sudo umount ${BACKUP_MOUNT_TARGET}
unset RESTIC_PASSWORD
unset SYNO_PASS
}
echo "Current date: $( date )"
# Can I ping the nas?
echo "Pinging the NAS 10 times"
ping -c 10 $NAS_IP > /dev/null && echo "up... proceeding" || ( echo "NAS down.";exit 1)
# Get username and password from key chain
SYNO_USER=$( secret-tool lookup synology username )
SYNO_PASS=$( secret-tool lookup synology password )
if isPathMounted "${BACKUP_MOUNT_TARGET}";
then
echo "${BACKUP_MOUNT_TARGET} is mounted"
else
# Check if the directory exists locally, otherwise create it
[ -d ${BACKUP_MOUNT_TARGET} ] || sudo mkdir ${BACKUP_MOUNT_TARGET}
sudo mount -t cifs \
-o username=${SYNO_USER},password="${SYNO_PASS}",vers=2.0,uid=${LOCAL_USER_ID},gid=${LOCAL_GROUP_ID},noauto,user \
"//192.168.1.10${SYNOLOGY_PATH}/" \
"${BACKUP_MOUNT_TARGET}"
fi
runResticBackup
if isPathMounted "${BACKUP_MOUNT_TARGET}";
then
sudo umount ${BACKUP_MOUNT_TARGET}
fi