Skip to content

PR 1: backup role with borgmatic + NFS-to-UniFi rsync

jedmund requested to merge jedmund/backup-role-pr1 into main

Created by: jedmund

Summary

First PR in a 4-PR series adding scheduled backups to the homelab. This one establishes the plumbing: borgmatic running in a container on nuc-mini, snapshotting /opt/docker to a local Borg repo, rsync'ing the repo to an NFS-mounted UniFi Drive share where the existing UniFi to Backblaze sync ships it offsite.

nuc-mini
├── borgmatic container ──[local repo]──▶ /var/backup/borg
└── after_actions: rsync ──▶ /mnt/nas/backup (NFS mount of UniFi share)


                                       existing UniFi Drive to Backblaze

In scope

  • Borgmatic container, internal cron at 02:00 daily
  • keep_daily: 30 retention
  • repokey-blake2 encryption, passphrase via vault
  • NFS mount of UniFi share via systemd automount (non-blocking on boot)
  • Post-backup rsync runs inside the container via after_actions
  • /opt/docker source path, /opt/docker/musicbrainz excluded (reproducible from upstream)
  • Custom Dockerfile extending ghcr.io/borgmatic-collective/borgmatic with rsync and nfs-common

Not in scope here (subsequent PRs)

  • Database consistency: PR 2 adds Borgmatic's native PostgreSQL and MongoDB hooks plus custom before_backup scripts for CouchDB and SQLite. Don't trust DB restores from snapshots taken before PR 2 ships.
  • Web UI: PR 3 adds borg-ui with native PocketID OIDC at backup.atelier.house.
  • Monitoring: PR 4 adds Healthchecks.io dead-man's-switch plus Netdata scrape of borgmatic's Prometheus exporter.

Commits

  1. backup: add role for borgmatic local-repo snapshots: role itself plus deploy playbook
  2. infra: wire backup into orchestration: inventory group plus all.yml import
  3. Makefile: add deploy-backup target
  4. backup: lock in real UniFi NAS values: NAS at 192.168.1.3, Homelab share

Pre-deploy checklist

Before running make deploy-backup for the first time:

  1. Create the vault file group_vars/backup/vault.yml:
    borg_passphrase: <strong random string, 32+ chars>
    Then ansible-vault encrypt group_vars/backup/vault.yml. Save the passphrase outside the repo too, because losing it means losing the repo permanently.

The NAS share, IP, and NFS export path are already locked in via commit 4.

Bootstrap (one-time, after first deploy)

ssh nuc-mini

# Initialize the empty repo
docker exec -it borgmatic borgmatic rcreate --encryption repokey-blake2

# Trigger the first backup manually (will take hours)
docker exec borgmatic borgmatic --verbosity 1

Subsequent runs happen on the internal 02:00 cron.

Test plan

  • make deploy-backup completes with no errors
  • /mnt/nas/backup is mounted (mount | grep nas) and writable
  • docker logs borgmatic shows the cron picking up the schedule
  • After bootstrap init plus first manual run, docker exec borgmatic borg list /repo shows at least one archive
  • ls /mnt/nas/backup/borg-nuc-mini/ shows segment files matching /var/backup/borg/
  • Force a config redeploy and confirm the handler restarts the stack with recreate: always
  • Reboot nuc-mini and confirm the automount doesn't block boot if NAS is unreachable

Merge request reports

Loading