Restic-backed backups using a many-to-many repository/job model. - repository = destination: restic repository URL verbatim (s3, local, removable device), backend credentials via env passthrough, retention policy, and an optional per-repository ntfy notify channel - job = source set: paths, sqlite and postgres dumps (consistent .backup / pg_dump instead of torn live-file copies), pushed to one or more repos - systemd timer per job, per-repo + per-job flock serialisation, restic check with read_data_subset for rotating integrity verification Service roles declare what to back up (ntfy_backup_*, uptime_kuma_backup_*); the inventory declares where.
22 lines
653 B
Django/Jinja
22 lines
653 B
Django/Jinja
[Unit]
|
|
Description=Backup job %i
|
|
After=network-online.target
|
|
Wants=network-online.target
|
|
|
|
[Service]
|
|
Type=oneshot
|
|
ExecStart={{ backup_script_path }} %i
|
|
|
|
# Creates /run/backup for the per-repository lock files, and removes it on
|
|
# stop. /run is a tmpfs, so the directory cannot simply be created once.
|
|
RuntimeDirectory=backup
|
|
RuntimeDirectoryMode=0700
|
|
|
|
# Backups are I/O heavy and never urgent: stay out of the way of live services.
|
|
Nice=10
|
|
IOSchedulingClass=idle
|
|
|
|
# A hung run holds the repository lock and blocks every other job against the
|
|
# same destination, so it must be killed rather than left to hang forever.
|
|
TimeoutStartSec={{ backup_timeout }}
|