Skip to content

Powered by Grav

Backup retention policy

Backup retention policy

multiback/mybackup retention is time-based: after each backup run, anything older than the configured window is removed, while every chain inside the window stays intact. Two variables drive it, both validated and defaulted in _validate_or_default_duration.

SH
export KEEP_WITHIN="3M"             # how long to keep backups
export FULL_BACKUP_FREQUENCY="28D"  # how often to take a new full backup

These live in the relevant paths.txt (or are inherited from a credential file's template). They are not in any /etc/boa/* file — that path does not exist.

KEEP_WITHIN

How long all backup files (full + incremental) are retained.

  • Accepted units: M (months) or Y (years).
  • Default: 3M.
  • A value not matching the months/years form falls back to the default. The validator additionally enforces the M/Y-only rule specifically for KEEP_WITHIN (a days/weeks value is rejected and reset to default).

FULL_BACKUP_FREQUENCY

How often a new full backup is taken; between fulls, runs are incremental.

  • Accepted unit: D (days).
  • Range: 7D to 60D (enforced).
  • Default: 28D.
  • Out-of-range or wrong-unit values fall back to 28D.

Both variables default from script-level constants when unset: _DEFAULT_KEEP_WITHIN="3M", _DEFAULT_FULL_BACKUP_FREQUENCY="28D". On the legacy AWS-S3 tools the equivalents are _AWS_TTL and _AWS_FLC — see Legacy backboa.

Time-based cleanup

Age-based cleanup runs remove-older-than:

SH
duplicity remove-older-than "${KEEP_WITHIN}" --force "${_BACKUP_TARGET}"

This deletes every full and incremental older than KEEP_WITHIN, then runs collection-status. It is invoked by the cleanup verb (_cleanup) and by the _weekly_cleanup path inside a backup run.

The weekly cleanup fires only when:

  • an archive log exists;
  • today is _DOW=7;
  • today's cleanup has not already run;
  • the cache is warm.

Within the retention window every chain is kept whole, so a restore to any point in the window resolves without reconstruction.

To preview a pass without deleting anything, run the same age command by hand with --dry-run appended:

SH
duplicity remove-older-than "${KEEP_WITHIN}" --force "${_BACKUP_TARGET}" --dry-run

It reports every set that falls outside the KEEP_WITHIN window while leaving the bucket untouched — handy for confirming a retention setting before it runs live. This is distinct from the test verb, which runs cleanup --dry-run: a connectivity and broken-chain check, not a retention preview.

purge is a full wipe, not a retention cleanup

The cleanup verb applies KEEP_WITHIN age-based retention. The purge verb is different and destructive: it runs

SH
duplicity remove-all-but-n-full 0 --force "${_BACKUP_TARGET}"

Keeping zero fulls means every backup set in the bucket is deleted (_wipe, "wipe the bucket completely"), after a repair pass and followed by a collection-status.

Use purge only to empty a bucket deliberately; it is not an age-based trim. So remove-all-but-n-full is used — by purge — and the only age-based path is remove-older-than.

Per-tenant local DB-dump retention (separate concern)

Tenants also keep local-disk DB dumps under /data/disk/<user>/static/files/dbackup/, distinct from the off-site copies. Default retention is 14 days, overridable per tenant via a single integer (days) in:

TXT
/data/disk/<user>/static/control/dBackupCycle.info

The host-level local SQL dump tree under /data/disk/arch/sql/ is pruned separately by mysql_backup.sh using _DB_BACKUPS_TTL (default 14 days; 3 days in basic mode) — see Database.

Local config-snapshot vault retention (separate concern)

/var/backups/dragon/ (root from ${_vBs:-/var/backups}) is the local pre-change safety vault. The nightly 90-global-post.sh prunes its top-level entries — each entry is removed wholesale once its own mtime exceeds 7 days — with a single exception for config:

SH
find /var/backups/dragon/* -maxdepth 0 ! -name config -mtime +7 -exec rm -rf {} \;

/var/backups/dragon/config/ is a permanent archive, never auto-pruned; trimming it is an operator decision, by design.

What lands there:

  • pre-rewrite snapshots of /root/.barracuda.cnf and every /root/.*.octopus.cnf (taken by BARRACUDA before its first on-the-fly cnf edit, and by OCTOPUS before _satellite_cnf);
  • /root/.my.cnf and /root/.my.pass.txt.

All via the shared _backup_to_dragon helper: one chmod-0700 subdirectory per run named YYYY-MM-DD_HH-MM-SS, keeping the earliest pristine copy of each file (never overwritten later in the run).

On a run's first snapshot, any loose files still at the top of config/ (legacy flat *-pre-* snapshots) are swept into config/archive/.

The four auto* OS-upgrade tools (autobeowulf, autochimaera, autodaedalus, autoexcalibur) inline the same subdirectory scheme.

The snapshot mechanism itself is documented on the control-file system overview — this page only owns the retention rule.

Do not conflate the two dragon subtrees: /etc/mysql/my.cnf pre-upgrade copies still go to /var/backups/dragon/t/my.cnf-pre-<serial>-<version>-<timestamp> and, living outside config/, fall under the 7-day rule — the whole t/ subtree is removed once untouched for 7 days.

The off-site global path-set includes /var/backups/dragon (see Backups overview), so these snapshots also ride the off-site backup, where the normal KEEP_WITHIN window applies.

Cost vs. retention

Longer KEEP_WITHIN means a larger provider bill. Practical bands:

Use case KEEP_WITHIN FULL_BACKUP_FREQUENCY
Development host 1M 14D
Standard production 3M (default) 28D (default)
Compliance / data-residency 1Y 28D
Long-term archive out-of-band copy n/a

For multi-year archival, take an out-of-band multiback snapshot to a separate cold tier rather than extending KEEP_WITHIN indefinitely.

© 2026 BOA Documentation. All rights reserved.