
How to Automate Linux Backups Using rsync and systemd
Automated backups do not need to be complicated. This guide shows how to use rsync with a small Bash script, a systemd service and a systemd timer to run reliable scheduled Linux backups with logs you can actually inspect.
Why use rsync with systemd timers?
rsync is efficient because it only copies changes. systemd timers are useful because they are logged, manageable with systemctl, and easier to audit than a forgotten cron line hiding in the weeds.
Efficient
rsync copies changed files rather than blindly copying everything every time.
Logged
systemd service output can be checked with journalctl.
Repeatable
Service and timer units make the backup schedule clear and versionable.
Example backup plan
This example backs up a website directory from one Linux server to another backup location over SSH.
| Item | Example |
|---|---|
| Source | /var/www/example.com/ |
| Destination | backup@example-backup:/srv/backups/example.com/ |
| Schedule | Daily at 02:30 |
| Method | rsync -aHAX --delete over SSH |
| Logs | journalctl -u website-backup.service |
--delete makes the destination match the source. That is useful, but dangerous if your source is wrong. Test without --delete first.Create the backup script
Create a script at /usr/local/sbin/website-backup.sh.
sudo nano /usr/local/sbin/website-backup.sh
#!/usr/bin/env bash
set -euo pipefail
SOURCE="/var/www/example.com/"
DEST="backup@example-backup:/srv/backups/example.com/"
LOG_TAG="website-backup"
echo "[$(date -Is)] Starting backup"
rsync -aHAX --numeric-ids --delete \
--exclude 'cache/' \
--exclude 'tmp/' \
"$SOURCE" "$DEST"
echo "[$(date -Is)] Backup completed"
Make it executable:
sudo chmod 750 /usr/local/sbin/website-backup.sh
sudo chown root:root /usr/local/sbin/website-backup.sh
Test the script manually
[2026-05-03T02:30:00+01:00] Starting backup
sending incremental file list
index.php
wp-content/uploads/2026/05/image.jpg
sent 184,332 bytes received 2,214 bytes 373,092.00 bytes/sec
total size is 812,449,203 speedup is 4,355.12
[2026-05-03T02:30:04+01:00] Backup completedCreate a systemd service
Create a oneshot service. A oneshot service runs a task and exits, which is ideal for backup scripts.
sudo nano /etc/systemd/system/website-backup.service
[Unit]
Description=Backup example.com website with rsync
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/website-backup.sh
Nice=10
IOSchedulingClass=best-effort
IOSchedulingPriority=7
[Install]
WantedBy=multi-user.target
Reload systemd and run the service once:
sudo systemctl daemon-reload
sudo systemctl start website-backup.service
sudo systemctl status website-backup.service
● website-backup.service - Backup example.com website with rsync
Loaded: loaded (/etc/systemd/system/website-backup.service; static)
Active: inactive (dead) since Sun 2026-05-03 02:30:04 BST; 8s ago
Process: 18422 ExecStart=/usr/local/sbin/website-backup.sh (code=exited, status=0/SUCCESS)Create a systemd timer
The timer controls the schedule. This example runs daily at 02:30 and catches up if the server was powered off at the scheduled time.
sudo nano /etc/systemd/system/website-backup.timer
[Unit]
Description=Run website backup daily
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
Unit=website-backup.service
[Install]
WantedBy=timers.target
Enable and start the timer:
sudo systemctl daemon-reload
sudo systemctl enable --now website-backup.timer
NEXT LEFT LAST PASSED UNIT ACTIVATES
Mon 2026-05-04 02:30:00 BST 8h left Sun 2026-05-03 02:30:00 BST 16h ago website-backup.timer website-backup.serviceCheck backup logs
Because the backup runs through systemd, you can inspect recent runs with journalctl.
sudo journalctl -u website-backup.service -n 50 --no-pager
May 03 02:30:00 web01 systemd[1]: Starting Backup example.com website with rsync...
May 03 02:30:00 web01 website-backup.sh[18422]: [2026-05-03T02:30:00+01:00] Starting backup
May 03 02:30:04 web01 website-backup.sh[18422]: sent 184,332 bytes received 2,214 bytes
May 03 02:30:04 web01 website-backup.sh[18422]: [2026-05-03T02:30:04+01:00] Backup completed
May 03 02:30:04 web01 systemd[1]: website-backup.service: Deactivated successfully.Test restoring from the backup
A backup is not proven until you can restore it. Test into a temporary location first.
mkdir -p /tmp/restore-test
rsync -av backup@example-backup:/srv/backups/example.com/ /tmp/restore-test/
drwxr-xr-x 6 root root 4096 May 3 02:31 .
drwxrwxrwt 18 root root 4096 May 3 02:35 ..
-rw-r--r-- 1 root root 405 May 3 02:31 index.php
drwxr-xr-x 8 root root 4096 May 3 02:31 wp-admin
drwxr-xr-x 12 root root 4096 May 3 02:31 wp-contentBackup safety checklist
- Use SSH keys for automated remote backups.
- Restrict the backup user on the destination server where possible.
- Test without
--deletebefore enabling destructive sync behaviour. - Monitor logs and failed units with
systemctl --failed. - Test restores regularly, not just backups.
- Keep at least one backup copy separate from the source server.
Useful next steps
These guides help with the commands used in this backup workflow.
Do not just create backups, verify them
A backup that has never been checked is more of a hopeful folder than a recovery plan. Add simple verification steps after each backup run.
# Check backup directory size
du -sh /backup/example-site/
# Check recent files exist
find /backup/example-site/ -type f -mtime -1 | head
# Compare source and destination with a dry run
rsync -avhn --delete /var/www/example/ /backup/example-site/
Frequently Asked Questions
Should I use rsync for Linux backups?
rsync is a good choice for file-level backups because it can copy only changed files and preserve ownership, permissions and timestamps.
What is the advantage of a systemd timer for backups?
A systemd timer can schedule backups with logging and service integration, making it more manageable than a simple one-line cron job.
Should I use rsync --delete?
Use --delete only when the destination should exactly mirror the source, and always test with --dry-run first.
How do I know a backup worked?
Check the systemd timer logs, rsync exit code, destination files and perform occasional restore tests.