I recently got more concerned about what is happening in the US since a certain president He-Who-Must-Not-Be-Named and what this does in the world and my personal life. I was already on a streak, cutting loose from BIG-TECH social media like META’s β€œsuite” and Google. This was also for privacy concerns.

I got concern about having all my data, partly client side encrypted but partly not, stored in the USA with Dropbox. I really liked Dropbox because it has a great adoption rate in other apps and products. But I did not like it that all my data was in the US. And with the recent presidency of He-Who-Must-Not-Be-Named, I got more concerned about my data with Dropbox.

Finding a European alternative with the same level of integration in software and services as Dropbox is a challenging task. Not that these services are inferior, but integrating them can sometimes be difficult. My goal was to achieve incremental backups of my shared folders on a Synology NAS and have the sync folder from my cloud storage synchronised with the Synology NAS.

This would be typically done with Hyperbackup for incremental backups and Cloud Sync for your sync folder. Most of the services listed there are either US-based, expensive, no up to the job, etc. A least for me.

After looking around and comparing European-based cloud providers, I got my eye on Jottacloud. This is a Norwegian cloud provider which is fast, in Europe of course, nice supporting clients for iOS and macOS (Yes, also US BIG-TECH, but I love Apple, there is nothing that compares with Apple Products. And I think Apple is doing a better job on privacy), has a great deal on β€œunlimited” storage space. The only downside Jottacloud has, they don’t (like Dropbox) have zero-knowledge encryption. If they had it, would enhance privacy a lot… But since they are in Europe with strict privacy laws, I took that as a step forward compared to the US-based Dropbox. Plus, the unlimited storage deal at JottaCloud is the same price as the 2 TB deal I had at Dropbox. Just a hint: if you look around on the internet you can find Jottacloud deals. I got a deal with 15% off for the first year.

Jottacloud also runs on 100% renewable energy, if you care for such a thing (I do).

Jottacloud is not one of the default services supported by Synology in their backup suite and other software. This is a shame, but there is a way to still create nice incremental backups of your shared folders to Jottacloud directly from your Synology.

This is achieved using a brilliant free application called Restic. Restic is a free, open-source backup tool offering secure, efficient, and flexible data protection. It supports multiple storage backends, including cloud services, and features encryption, deduplication, and compression. Restic is user-friendly and suitable for various operating systems, making it ideal for both personal and professional backup needs.

To access Jottacloud with Restic, I used Rclone. Rclone is a versatile command-line tool for managing cloud storage, offering features such as file syncing, encryption, and compression. It supports over 70 cloud services, including Jottacloud, Google Drive, and Amazon S3, and is ideal for automating backups and data transfers across various platforms with ease and reliability.

Rclone and Restic are not natively available on your Synology. There are scripts and methods to install them via the NAS shell. However, I am a fan of Docker. Since I own a Synology that supports Docker, which Synology refers to as β€œContainer Manager” in their DSM, I implemented Restic and Rclone using Docker.

Docker is a containerisation platform that enables efficient deployment and management of applications. It allows developers to package software into portable containers, ensuring consistent performance across environments. Docker streamlines development, testing, and deployment processes, enhancing flexibility and scalability for a wide range of applications and services.

If your Synology does not support Docker, you can still achieve what is described below by using a Raspberry Pi. You can in install your favourite OS (mine is Ubuntu on the PI) and install Docker within Ubuntu on this beautiful device. If you have done so, you can connect your shared folders using NFS to the Ubuntu installation you can use the method that is described below.

Okay, how is this done? Five years ago, I came a cross of a nice five-year-old (at that time) project on GitHub. This already made a docker container including Restic and Rclone. At the time It was not recently maintained (older Restic version, not build with the latest package) I decided to fork this project and update and enhance it. My GitHub repository can be found here. The pre-build docker images for ARM and AMD can be found here.

I recently added an option to set up a sync with your sync-folder, supported by your cloud provider. I will explain that later. First, we set up the container in Docker.

Below you find a template docker-compose.yml file. This uses the stable build for the image. If you like the development tree, use the marc0janssen/restic-backup-helper:develop as an image reference.

version: '3'

services:
  restic-remote:
    container_name: restic-remote
    image: marc0janssen/restic-backup-helper:latest
    healthcheck:
      test: ["CMD", "restic", "-r", "rclone:jottacloud:backups", "cat", "config"]
      interval: 15m
      timeout: 10s
      start_period: 1m
      start_interval: 10s
    restart: always
    hostname: supernode
    cap_add:
      - DAC_READ_SEARCH
      - SYS_ADMIN
    devices:
      - /dev/fuse
    environment:
      - RESTIC_PASSWORD=YOUR_PASSWORD_HERE
      - RESTIC_TAG=YOUR_TAGS_HERE
      - RESTIC_FORGET_ARGS=--prune --keep-hourly 24 --keep-daily 7 --keep-weekly 5 --keep-monthly 12 --keep-yearly 10
      - RESTIC_REPOSITORY=rclone:jottacloud:backups
      - RESTIC_JOB_ARGS=--exclude-file /config/exclude_files.txt
      - BACKUP_CRON=0 1,13 * * *
      - BACKUP_ROOT_DIR=/volume1/data
      - MAILX_RCPT=your_mail@here.tld
      - MAILX_ON_ERROR=OFF
      - CHECK_CRON=37 1 1 * *
      - RCLONE_CONFIG=/config/rclone.conf
      - SYNC_JOB_FILE=/config/sync_jobs.txt
      - SYNC_JOB_ARGS=--exclude-from exclude_sync.txt
      - SYNC_CRON=*/10 * * * *
      - TZ=Europe/Amsterdam
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /path/to/your/hooks:/hooks
      - /path/to/your/log:/var/log
      - /path/to/your/restore:/restore
      - /path/to/your/config/:/config
      - /path/to/your/config/msmtprc:/etc/msmtprc
      - /volume1/data:/volume1/data

Set up the following tree for your installation:

./
β”œβ”€β”€ config
β”‚   β”œβ”€β”€ exclude_files.txt
β”‚   β”œβ”€β”€ exclude_sync.txt
β”‚   β”œβ”€β”€ include_files.txt
β”‚   β”œβ”€β”€ msmtprc
β”‚   β”œβ”€β”€ rclone.conf
β”‚   └── sync_jobs.txt
β”œβ”€β”€ hooks
β”œβ”€β”€ log
β”‚   β”œβ”€β”€ backup-error-last.log
β”‚   β”œβ”€β”€ backup-last.log
β”‚   β”œβ”€β”€ check-error-last.log
β”‚   β”œβ”€β”€ check-last.log
β”‚   └── cron.log
└── scripts
    └── docker-compose.yml
  • config

    • exclude_files.txt - files/folders to exclude from your Restic backups
    • exclude_sync.txt - files/folders to exclude from your Rclone bisync
    • include_files.txt - files/folders to include from your Restic backups
    • msmtprc - configuration file for the msmtp-client
    • rclone.conf - configuration file for your rclone client
    • sync_jobs.txt - configuration file with sync jobs for rclone
  • hooks

    • pre-backup.sh - script started before backup
    • post-backup.sh - script started after backup
    • pre-check.sh - script started before checking the repository
    • post-check.sh - script started after checking the repository
    • pre-sync.sh - script started before sync of sync folder
    • post-sync.sh - script started after sync of sync folder
  • log

    • backup-error-last.log - Most recent backup error log
    • backup-last.log - Most recent backup log
    • check-error-last.log - Most recent repository check error log
    • check-last.log - Most recent repository check log
    • cron.log - Active cron log
    • sync-error-last.log - Most recent sync error log
    • sync-last.log - Most recent sync log
  • scripts

    • docker-compose.yml - Container Configuration file

The first thing to do is to create a rclone config file. I, personally, do this within Ubuntu on a Raspberry Pi, where I installed rclone. Run the follow command and follow its instructions:

$ rclone config

To choose the following option, n) New remote. Enter a name for your new remote. Since I use Jottacloud, I entered Jottacloud. A list of cloud providers is shown. Jottacloud is number 25. Enter this number on the CLI. The next question is if you have an advanced configuration, for me, this answer is the default no. After this, you have to select an authentication type. Choose 1 Standard authentication. Now you have to generate a Personal login token. This can be generated here. Paste this token in the CLI and press enter. The next question is if you use a non-standard device or mountpoint. For a backup is n) No (default) but if you want to use the sync option of this image I advise you to select y) Yes and pick the Sync mount point. For now, select n) No (default). Confirm your config. Your new created rclone.conf can be found in:

~/.config/rclone/rclone.conf

Copy this file to the /config/ directory of the tree shown above.

Remember to set RESTIC_REPOSITORY and healthcheck: in the docker-compose.yml to the path of your repository. For me, this would be:

rclone:jottacloud:backups

NOTE: If you plan to back up multiple nodes with their containers. And you decide to have a rclone and Restic package on your client desktop or laptop. And also connect to the repository, ALWAYS have a new separate rclone.conf file. Your token will get invalid if you connect with multiple nodes to use the same token.

NOTE: Also make sure the rclone.conf file is writable for the restic-helper-container, since Rclone will update the expiration date for the token. If it fails to do so, your token will get invalid.

If the token gets invalid, you can update your token with:

$ rclone config reconnect jottacloud:

Where jottacloud: is the name of your remote.

The next stop is to create a configuration file for the mail option in the container. This file should look like the following example.

account default
from _mail_from@here.tld_
host _smtp_host.here.tld_
port 587
tls on
auth on
user _login@here.tld_
password _Pa55w0rd_h3r3_

Next stop is to create a configuration file for the files you would rather not back up from your source. A basic file for a Synology would be something like the following example. Of course, you can add your exclusions to the file exclude_files.txt.

*@eaDir*
.DS_Store
**/#recycle

Setting the BACKUP_ROOT_DIR environment variable in the docker-compose.yml file to a shared directory of your Synology would only back up that directory, ex.: BACKUP_ROOT_DIR=/volume1/data. That is probably not what you want. You most likely want to back up more shared directories. If you choose BACKUP_ROOT_DIR=/volume1 to do so, I would back up ALL the stuff in /volume1 and that is also not what we want.

To come around this, you leave BACKUP_ROOT_DIR= empty and set up include_files.txt. This file holds the files and directories you would like to back up.

/volume1/content
/volume1/docker
/volume1/documents
/volume1/homes
/volume1/homevideo
/volume1/inbox
/volume1/logging
/volume1/photo
/volume1/programming
/volume1/software

Edit your docker-compose.yml with the following line.

- RESTIC_JOB_ARGS=--exclude-file /config/exclude_files.txt --files-from /config/include_files.txt

We still need to create a repository in the cloud, Jottacloud that is. Here we need to use Restic on the linux CLI. I do this again from an Ubuntu installation on a Raspberry Pi. The command you have to execute is:

$ restic -r rclone:jottacloud:backups init
  • rclone - This is the protocol we like to use
  • jottacloud - This is the remote you created with rclone
  • backups - This is a target that will be created in the Jottacloud Archive section.

Now set up the rest of the docker-compose.yml file and start your container. The following command will get you started to start the container.

$ docker-compose -p "restic-backup-helper" -f /path/to/your/docker-compose.yml up -d --remove-orphans

Of course, if you use Portainer. You can create a stack and past the content of the docker-compose.yml in the editor and start your container like so.

Portainer is an open-source container management platform offering a user-friendly graphical interface for managing Docker and Kubernetes environments. It simplifies deployment, monitoring, and maintenance of containerised applications, providing a unified dashboard for multiple environments and supporting various container technologies like Docker Swarm and Azure ACI.

If you set up the container correctly, you would see something like this.

🌟 *************************************************
🌟 ***           Restic Backup Helper            ***
🌟 *************************************************
πŸš€ Starting container Restic Backup Helper 'kish' on: 2025-03-25 19:03:16...
πŸ“¦ Release: 1.6.52-0.17.3-dev
πŸ” Checking repository status...
ℹ️ Repository check status: 0
βœ… Restic repository 'rclone:jottacloud:backups' attached and accessible.
⏰ Setting up backup cron job with expression: 30 17 * * 6
⏰ Setting up sync cron job with expression: */5 * * * *
βœ… Container started successfully.

In this example, the backup will be executed every Saturday at 17:30. The repository can be found on rclone:jottacloud:backups. This will back it up to the archive part of Jottacloud.

If there is a successful backup, you will see output like this.

ℹ️ Pre-backup script not found...
πŸ”„ Starting Backup at 2025-03-25 17:30:00
πŸ“¦ Performing backup of /volume1/inbox...
βœ… Backup Successful
🏁 Finished backup at 2025-03-25 17:30:38 after 0m 38s
ℹ️ Post-backup script not found...

So your backup is nice and running. In the example above, there a second CRON with runs every 5 minutes. This is the sync folder the connects to the Jottacloud synchronisation part of the cloud.

The setting this up runs rclone config again, runs through the same steps as shown above but if the question comes for a non-standard device or mountpoint. Choose YES and choose the option Sync. This gives Rclone access to the synchronisation part of Jottacloud. The advantage is that whatever you sync from your Synology to Jottacloud, the Jottacloud software will pick this up and sync this to your other devices. If you have the Jottacloud software installed.

Don’t forget to pick a new TOKEN, and after you generate that new config file (with two remotes) copy it to /config/ of your container. Also pick a new name for that remote like jottasync.

Set up the following environment variables in the docker-compose.yml file.

      - SYNC_JOB_FILE=/config/sync_jobs.txt
      - SYNC_JOB_ARGS=--exclude-from exclude_sync.txt
      - SYNC_CRON=*/10 * * * *

The sync_jobs.txt should contain something like this.

# SYNC JOBS
# SOURCE;DESTINATION

/volume1/inbox;jottasync:/inbox
/volume1/photo;jottasync:/photo
/volume1/documents;jottasync:/documents

It is the source and destination of the data you like to sync.

The exclude_sync.txt should contain the files and directories you don’t like to sync.

# Exclude system directories
@eaDir/**
\#recycle/**

# Exclude macOS system files
.DS_Store

And set your SYNC_CRONwith the desired interval of your sync.

If all is well set up, you will see output for the first run only like the following example.

πŸ”€ Performing sync of /volume1/inbox <-> jottasync:/inbox...
❌ Sync Failed with Status 2
🚨 Starting recovery procedure...
πŸ”„ Step 1: Updating from /volume1/inbox to jottasync:/inbox
πŸ”„ Step 2: Updating from jottasync:/inbox to /volume1/inbox
πŸ”„ Step 3: Performing full resync between /volume1/inbox and jottasync:/inbox
βœ… Recovery Successful - All steps completed
πŸ“Š Recovery Exitcode Summary: Sourceβ†’Dest=0, Destβ†’Source=0, Resync=0
🏁 Finished sync at 2025-03-25 15:55:39 after 0m 39s
πŸ”€ Performing sync of /volume1/photo <-> jottasync:/photo...
❌ Sync Failed with Status 2
🚨 Starting recovery procedure...
πŸ”„ Step 1: Updating from /volume1/photo to jottasync:/photo
πŸ”„ Step 2: Updating from jottasync:/photo to /volume1/photo
πŸ”„ Step 3: Performing full resync between /volume1/photo and jottasync:/photo
βœ… Recovery Successful - All steps completed
πŸ“Š Recovery Exitcode Summary: Sourceβ†’Dest=0, Destβ†’Source=0, Resync=0
🏁 Finished sync at 2025-03-25 15:55:39 after 0m 39s
πŸ”€ Performing sync of /volume1/documents <-> jottasync:/documents...
❌ Sync Failed with Status 2
🚨 Starting recovery procedure...
πŸ”„ Step 1: Updating from /volume1/documents to jottasync:/documents
πŸ”„ Step 2: Updating from jottasync:/documents to /volume1/documents
πŸ”„ Step 3: Performing full resync between /volume1/documents and jottasync:/documents
βœ… Recovery Successful - All steps completed
πŸ“Š Recovery Exitcode Summary: Sourceβ†’Dest=0, Destβ†’Source=0, Resync=0
🏁 Finished sync at 2025-03-25 15:55:39 after 0m 39s

The first sync will β€œfail” because the caches are not yet up to date. The script will handle this correctly for the second run of your sync. Like you see below.

ℹ️ Pre-sync script not found...
πŸ”€ Performing sync of /volume1/inbox <-> jottasync:/inbox...
βœ… Sync Successful
🏁 Finished sync at 2025-03-25 19:30:11 after 0m 11s
πŸ”€ Performing sync of /volume1/photo <-> jottasync:/photo...
βœ… Sync Successful
🏁 Finished sync at 2025-03-25 19:30:24 after 0m 24s
πŸ”€ Performing sync of /volume1/documents <-> jottasync:/documents...
βœ… Sync Successful
🏁 Finished sync at 2025-03-25 19:30:33 after 0m 33s
ℹ️ Post-sync script not found...

Note: The default for Rclone bisync if that is 50% more difference between the source and the destination is found, Rclone will fail and exit. The script syncing your data will then try to copy all data back from the source to the destination and from destination to source. This will look like all syncs did not work, but actually, it is a safety measure. If you don’t want this, add --force to your SYNC_JOB_ARGS.

Here are some examples to use Restic inside the container from the host.

This command will list all snapshots with Restic from a container restic-remote.

 $ sudo docker exec -ti restic-remote restic snapshots

This command generates the following output.

ID        Time                 Host        Tags        Paths            Size
-----------------------------------------------------------------------------------
9547a8f4  2025-03-21 16:33:45  eridu       eridu       /home/pi/docker  324.319 MiB
693fc4e7  2025-03-21 23:59:09  eridu       eridu       /home/pi/docker  324.366 MiB
a2db8a02  2025-03-22 18:00:00  eridu       eridu       /home/pi/docker  324.823 MiB
b3076cd0  2025-03-22 19:00:00  eridu       eridu       /home/pi/docker  324.476 MiB
187efc43  2025-03-22 20:00:00  eridu       eridu       /home/pi/docker  324.477 MiB
e50c1751  2025-03-22 21:00:00  eridu       eridu       /home/pi/docker  324.482 MiB

If you want to list the content of a snapshot, you use the following command.

$ sudo docker exec -ti restic-remote restic ls 	e50c1751 --long | grep mp3

This command will list all files in the snapshot e50c1751. The grep command will only show you all lines with mp3 in its path.

Restoring files from a snapshot is done with the following command.

$ sudo docker exec -ti restic-remote restic restore e50c1751 --target /data --include /mnt/data/

This command will restore from snapshot e50c1751 to target /data, but only the files from the path /mnt/data/

For all the information you need on Restic, check this website.

If this blog was any help to you, give away a free Lucky Four-Leaf Clover

βœοΈπŸ“