nyoncode/laravel-backup-manager

nyoncode/laravel-backup-manager

Powerful and extensible backup manager for Laravel applications: databases, files, encryption, integrity manifests and multi-destination storage.

0
Packagist stažení
0
Verzí
1.1.1
Aktuální verze
Závislosti
php ^8.3 ext-json * ext-openssl * illuminate/bus ^12.0|^13.0 illuminate/console ^12.0|^13.0 illuminate/contracts ^12.0|^13.0 illuminate/database ^12.0|^13.0 illuminate/filesystem ^12.0|^13.0 illuminate/queue ^12.0|^13.0 illuminate/support ^12.0|^13.0 nyoncode/laravel-package-toolkit ^2.1.1 symfony/finder ^7.0 symfony/process ^7.0

Incremental & deduplicated backups

Pro feature. Incremental/deduplicated backups require Backup Manager Pro. The free core can list snapshots but refuses to create, restore or verify them.

Every ordinary backup is a full, self-contained archive. Incremental backups instead store a snapshot whose file contents live in a shared, content-addressed blob pool — so only content that changed since the previous snapshot is uploaded, and content that repeats across backups is stored once.

This is ideal for a frequent cadence (hourly/daily) where storage and time matter. Full archives remain the reliable, standalone anchors; incrementals complement them, they don't replace them.

Mode is independent of scope. A profile's type (full / database / files) says what to back up; its mode (archive / incremental) says how to store it. Any scope can use either mode.

Enabling it

Set mode on a profile:

1'profiles' => [
2 'hourly' => [
3 'name' => env('APP_NAME'),
4 'type' => 'files',
5 'mode' => 'incremental', // ← store as a deduplicated snapshot
6 'files' => ['include' => [base_path()]],
7 'destinations' => ['s3'],
8 'path' => 'backups',
9 ],
10],

Then run it like any other profile:

1php artisan backup:run --profile=hourly

The command reports how much was deduplicated:

1Snapshot app-2026-07-19-020000-1a2b3c.manifest.json
2Mode Incremental snapshot
3Files 12,481
4Deduplicated 37 new, 12,444 reused (18.2 MB new content)
5Destinations s3

How it works

1{path}/
2 snapshots/
3 {name}.manifest.json one index per snapshot (lists every file + its hash)
4 blobs/
5 {algorithm}/{ab}/{digest} the content-addressed pool (one blob per unique content)
  • Every file is stored as a blob keyed by the hash of its content. Identical content — across files, snapshots, or runs — is stored exactly once.
  • A snapshot's manifest is its index: it lists every file with the hash that locates its blob. Because addressing is by content, each snapshot is self-sufficient given the pool — there is no fragile chain of increments to walk on restore.
  • Archive backups and snapshots coexist under the same path without collision.

Restore

Restore is identical to archive backups — the snapshot is reassembled from the pool transparently:

1php artisan backup:restore --profile=hourly # newest snapshot
2php artisan backup:restore app-2026-07-19-...manifest.json --profile=hourly

Restoring an older snapshot faithfully returns its historical content, even after newer snapshots exist, because each blob is addressed by content. All restore options apply: --database, --files, --only=, --unsafe, --no-verify. Verified restores check the snapshot's file-index anchor and every blob's checksum. See Restore.

Compression & encryption

Blobs honour the profile's compression and encryption settings: each blob is compressed and then encrypted, but still keyed by its plaintext hash, so deduplication is fully preserved and the bytes at rest are protected.

Treat the algorithm and key as fixed for a pool's lifetime, like a repository password. Changing them leaves earlier blobs unreadable by later snapshots that expect the new setting.

Retention & garbage collection

backup:clean prunes snapshots by the same policy as archives (GFS / simple + age / size caps), then reclaims the pool by reference-counted mark-and-sweep:

1php artisan backup:clean --profile=hourly --dry-run
1s3 would delete 3 backup(s)
2 app-2026-07-12-... 2026-07-12 02:00
3 app-2026-07-13-... 2026-07-13 02:00
4 app-2026-07-14-... 2026-07-14 02:00
5 blob pool would reclaim 214 blob(s) · 1.9 GB

A blob is deleted only when no surviving snapshot references it — pruning one snapshot never breaks another that shares content. The sweep is fail-closed: if any surviving manifest cannot be read, no blob is deleted. See Retention.

Run backup:clean when backups are not running. Like all mark-and-sweep collectors, it assumes a stable set of snapshots for the duration of the sweep.

Verify & monitor

  • backup:verify confirms a snapshot's file index, that every referenced blob is present, and that each blob (decrypted/decompressed) hashes to its recorded value — a real restorability check.
  • backup:list and backup:monitor count snapshots alongside archives, so a snapshot-only profile is never reported as empty. See CLI reference.

When to use which

Use case Recommended
Nightly full, kept for months archive (self-contained anchor)
Hourly/daily, storage-sensitive incremental
Pre-deploy rollback point small archive, database-only
Many near-identical hosts/backups incremental (cross-backup dedup)