Application recovery

Automate and alert on backups

Schedule backups with locking, deadlines, logs, and failure notifications that someone will act on.

10 minute lesson

~~~

A backup that depends on memory will eventually stop. You’ll be busy, then on vacation, then it’s been four months. Automation fixes that — and creates a new failure mode: jobs that break silently and keep “running” as no-ops for months. Automation must also make silence and repeated failure visible.

Wrap the backup with an honest exit

Create a wrapper result suitable for a scheduler:

if restic backup /srv/data; then
  printf '%s backup=success\n' "$(date -u +%FT%TZ)"
else
  status=$?
  printf '%s backup=failure status=%s\n' "$(date -u +%FT%TZ)" "$status" >&2
  exit "$status"
fi

The script logs a timestamped result line and, crucially, exits non-zero on failure. Schedulers and alerting can only react to what the script reports.

Schedule it with cron, capturing output:

# /etc/cron.d/backup
0 3 * * * root /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1

Cron is where silent failures breed. It runs with a minimal environment: a stripped PATH, no RESTIC_REPOSITORY, no RESTIC_PASSWORD_FILE. A script that works perfectly in your shell fails at 3 AM because the variables were only in your session. Export everything the job needs inside the script itself, and test by running it from a bare environment: env -i /usr/local/bin/backup.sh.

Test the failure path

Now force a permission and destination failure — make the repository unreachable, or revoke read access to /srv/data. Confirm the scheduler records non-zero status and the alert reaches the responsible person. An alert channel nobody checks is decoration. If you’ve never seen your backup alert fire, you don’t have alerting; you have optimism.

Alert on silence, not just errors

There’s a failure the error path can’t catch: the job never ran at all. Disabled cron, powered-off machine, deleted crontab. No run means no error means no alert.

A “job did not run” condition needs detection too. Alert on missing recent successful snapshots. The dead-man’s-switch pattern works well: the wrapper pings a monitoring URL after each success, and the monitor alerts when pings stop arriving:

restic backup /srv/data && curl -fsS https://hc-ping.com/6c2ea1d4-backup

Alternatively, a daily check that the newest snapshot is younger than 24 hours (restic snapshots --json plus a timestamp comparison) catches the same silence from the repository side.

Lesson completed

Take this course offline

Get every free book and course as PDF and EPUB files.

Get the download library →