How to automate Linux backups using rsync and systemd banner
Linux backup automation

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.

On this page
Quick answer

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.

Backup plan

Example backup plan

This example backs up a website directory from one Linux server to another backup location over SSH.

ItemExample
Source/var/www/example.com/
Destinationbackup@example-backup:/srv/backups/example.com/
ScheduleDaily at 02:30
Methodrsync -aHAX --delete over SSH
Logsjournalctl -u website-backup.service
Important: --delete makes the destination match the source. That is useful, but dangerous if your source is wrong. Test without --delete first.
Step 1

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

$ sudo /usr/local/sbin/website-backup.sh
[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 completed
Step 2

Create 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
$ 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)
Step 3

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
$ systemctl list-timers 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.service
Logs

Check 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
$ sudo journalctl -u website-backup.service -n 20 --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.
Restore testing

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/
$ ls -la /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-content
Safety tips

Backup safety checklist

  • Use SSH keys for automated remote backups.
  • Restrict the backup user on the destination server where possible.
  • Test without --delete before 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.
If you are backing up databases, dump or snapshot them properly first. Copying live database files with rsync can produce inconsistent backups.
Related

Useful next steps

These guides help with the commands used in this backup workflow.

Backup quality

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/
For important systems, schedule a restore test. The goal is not just to back up data, but to prove you can recover it.
FAQ

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.

$ practise_next --topic bash

Practise this next

Turn the guide into practice with a related quiz, builder, cheat sheet or learning path.