Community Solution

Build Reboot-Proof Scheduled rsync Backups on ZimaOS with Ofelia

A user moved weekly AppData and NAS backup scheduling into a persistent Portainer stack using Ofelia, rsync, and scripts stored on RAID storage.

The Schedule Needed to Live in Persistent Docker State

The author wanted weekly copies of AppData to a RAID 1 pool and a second copy from that pool to a continuously attached USB disk. Their system crontab and a community scheduling app did not retain tasks reliably across reboot, so they moved scheduling into a Portainer-managed Ofelia stack stored under persistent ZimaOS data.

The resulting design separated three layers: shell scripts on the RAID storage, an Ofelia container that supplied the schedule, and short-lived rsync containers that performed each copy.

Store Scripts and Logs on Persistent Storage

The example placed scripts under a path such as /media/RAID1/scripts. That directory was mounted read-write into the scheduler as /scripts. Logs were written beside the scripts so they could be inspected through Files or a network share after the job completed.

Every path in the example is installation-specific. Copying the author's RAID name without checking the actual mount path can send a backup to the wrong place or make the job silently fail.

Ofelia Supplied the Reboot-Persistent Schedule

The Portainer stack used the Ofelia image, set restart: always, mounted the script directory, and stored schedule labels with the container. The example scheduled AppData at 23:30 every Sunday and the general NAS data at 23:45.

ofelia.job-local.appdata.schedule: "0 30 23 * * 0"
ofelia.job-local.appdata.command: "/bin/sh /scripts/backup_appdata.sh"
ofelia.job-local.nas_home.schedule: "0 45 23 * * 0"
ofelia.job-local.nas_home.command: "/bin/sh /scripts/backup_nas_home.sh"

The author reported that the scheduler and its jobs returned within roughly a minute of reboot without requiring another SSH session.

The AppData Script Stopped Plex Before Copying

To reduce the chance of copying an actively changing Plex database, the script stopped Plex, ran rsync from a read-only AppData source mount, and restarted Plex afterward. The scheduler container installed a Docker CLI when needed and controlled sibling containers through the Docker socket.

Mounting /var/run/docker.sock gives the scheduler broad control over the Docker host. Running it as root and privileged further increases that authority. The thread presents this as the author's working design, not a least-privilege security model.

rsync --delete Creates an Exact Mirror, Not Versioned History

The example used rsync -avH --delete. The --delete option removes destination files that no longer exist at the source. That produces an exact mirror but can also replicate accidental deletion or corruption.

Test first without deletion, confirm source and destination mounts, and inspect the log before enabling an unattended schedule. A mirror on an always-connected USB disk is also not equivalent to an offline or immutable backup.

Reboot Persistence Did Not Solve USB Reconnection

The author separately requested that an attached USB disk stop appearing as a new disk after reboot. Ofelia preserves the job configuration, but a changed or unavailable mount path can still break the backup target. Stable storage identification and verifying mounts before rsync remain separate requirements.

FAQ

Why did this schedule survive reboot?

The job definitions lived in a restart-enabled Portainer stack and the scripts lived on persistent storage rather than in an ephemeral system crontab.

Does this create historical backup versions?

No. The documented rsync command creates a mirror and uses --delete. Version retention requires a different design.

Why stop Plex before copying AppData?

The author did so to reduce the risk of copying its database while it was being modified.