Backups & restore¶
What this is¶
Server backups copy chosen directories from a fleet host into the PiHerder host’s backup volume using rsync over SSH. Runs are jobs on Celery (not inside a web request), so a long rsync does not freeze the UI.
Why it exists¶
Homelab hosts hold compose data, configs, and media that are painful to rebuild. PiHerder makes backup repeatable, scheduled, audited, and restorable without maintaining a separate cron library on every Pi. You choose paths and policy; the control plane handles queueing and history.
What it is not¶
| Server backups (this page) | PiHerder self-backup |
|---|---|
| Files from fleet hosts | Config of the herder itself (DB, users, keys…) |
| Server → Backups UI | Settings → PiHerder backup |
Volume /backups (or host map) | Volume /herder_backups |
See Self-backup & DR for the control plane.
End-to-end: first backup you trust¶
- On the server: Edit → Features → enable Backups.
- Open Backups → add at least one source path that exists on the remote (e.g. a compose data directory).
- Confirm path policy is not blocking that prefix.
- Run backup (manual) once.
- Watch Jobs until success; open Audit for size summary.
- On the herder host, confirm files under the backup volume (Volumes).
- Restore wizard → dry-run for that source (no write).
- Only then enable a cron schedule.
Done when: success updates last_backup_at; you know how to reverse with dry-run first.
Full journey: Operator scenarios — Journey B.
Busy sources (vanished files)¶
On Frigate/NVR-style trees, rsync may hit code 24 (vanished files). From v1.2, PiHerder retries and can mark the source soft-OK instead of failing the whole job. Details: Troubleshooting — vanished files.
Enable backups¶
- Server Edit → Features → enable Backups.
- Open the server’s Backups page (ops-hero + source cards — same width as other host pages).
- Use header Configure for schedule, destination paths, and sources (there is no second “Full configure” under sources).
- Add source paths on the remote host (configure form lists current sources; empty only when none are set).
- Optional: destination override, retention, cron schedule (UI shows plain English next to the expression, e.g. “Daily at 02:00”).
- Path allow/deny — default deny of OS roots; optional prefixes.
How success is decided¶
| Outcome | Meaning |
|---|---|
| Success | Each source finishes with rc == 0 and no error classification; last_backup_at updates |
| Failed | Status failed, audit error details, last_backup_at not updated |
| After success | Open backup_failed notifications resolve |
rsync path¶
- Default:
--rsync-path "sudo -n rsync"(or local sudo) so a least-priv user can still read protected trees. - Root user / HAOS: plain
rsyncis auto-probed and used when sudo is not available.
Schedules¶
Enable + cron on the Backups page. Same server never runs two backups at once (Redis mutex); different hosts can run in parallel.
Why a mutex: overlapping rsync to the same destination corrupts snapshots and confuses retention.
From the Servers list you can multi-select hosts and run Backup in bulk (only hosts with backups enabled) — Bulk actions.
Restore wizard¶
Why dry-run first: restore writes onto the remote host. A preview reverse rsync shows what would change without committing.
- Backups page → restore for a source.
- Dry-run reverse rsync (preview).
- Confirm to apply.
- Path policy enforced; audit action
backup_restore.
Restore is privileged
You are writing back onto the remote host. Prefer dry-run first. Prefer restoring to a test path when learning.
Retention¶
Retention cleanup is a separate job type (retention) driven by configured keep rules. Why separate: deleting old trees is independent of “did tonight’s rsync succeed?”
Troubleshooting¶
Success/fail over time and dest-size growth: Reports.
Named-volume copy during Move a service uses the same Mountpoint rsync privilege as backing up /var/lib/docker/volumes. That is a Job, not a backup restore.