Download the PHP package webhubworks/craft-backup without Composer
On this page you can find all versions of the php package webhubworks/craft-backup. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download webhubworks/craft-backup
More information about webhubworks/craft-backup
Files in webhubworks/craft-backup
Package craft-backup
Short Description A plugin to backup your Craft CMS app.
License mit
Informations about the package craft-backup
Backup
The go-to backup package for Craft CMS, heavily inspired by spatie/laravel-backup. (Read why)\
Command-line only, database and files, compressed, encrypted, shipped off-site over SFTP, and pruned by a GFS retention policy (GFS what?).
If you've used laravel-backup on a Laravel project, you already know how this one feels. See Compared to spatie/laravel-backup for the side-by-side command and feature map.
No control-panel UI, no licensing fees. Schedule it from cron, forget about it. (Well, you might want to use the monitoring feature anyway.)
Requirements
- Craft CMS 4.4 or later (Craft 5 supported)
- PHP 8.1 or later
- A database supported by Craft itself (we delegate to
Craft::$app->db->backup()):
| Engine | Versions | Dump tool required on PATH |
|---|---|---|
| MySQL | 5.7.8+ / 8.0.5+ | mysqldump |
| MariaDB | 10.4.6+ | mysqldump |
| PostgreSQL | 13+ | pg_dump |
MongoDB is not supported (Craft itself runs on SQL). For everything else — encryption, SFTP, archive handling — we use only PHP extensions that ship with Craft's own requirements.
Installation
Configuration
config/backup.php is multi-environment aware ('*', 'dev', 'production' keys), just like general.php.
Review the defaults, add your targets, and you're ready to run.\ Encryption is off by default — see Encryption & restore below for how to turn it on and how to recover an archive.
Targets
Each entry under targets maps a name (freely chosen) to a driver config. Uploads run against every target; retention prunes each one independently. Use --only-to=<name> on backup/run or backup/clean to restrict to a single target.
| Driver | Description | Required keys | Optional keys |
|---|---|---|---|
local |
Writes into a directory on the same host | root (path or @alias) |
— |
sftp |
Uploads via SSH to a remote server | host, username, and either password or private_key |
port (22), passphrase, root (/backups), timeout (30) |
Environment variables
The published config/backup.php reads these out of .env via App::env() so secrets stay out of version control. Override any or none — unset values fall back to the defaults in the config file.
| Variable | Maps to | Purpose |
|---|---|---|
BACKUP_NAME |
name |
Prefix for generated archive filenames |
BACKUP_ARCHIVE_PASSWORD |
compression.password |
AES-256 password when compression.format = 'zip' |
BACKUP_ENCRYPTION_ENABLED |
encryption.enabled |
true/false/1/0 — enables the .tar.gz.enc envelope |
BACKUP_ENCRYPTION_KEY |
encryption.key |
Base64-encoded 32 bytes, required when encryption is enabled |
BACKUP_SFTP_HOST |
targets.<name>.host |
SFTP hostname |
BACKUP_SFTP_PORT |
targets.<name>.port |
SFTP port (defaults to 22) |
BACKUP_SFTP_USERNAME |
targets.<name>.username |
SFTP username |
BACKUP_SFTP_PASSWORD |
targets.<name>.password |
SFTP password (use this or the private key) |
BACKUP_SFTP_PRIVATE_KEY |
targets.<name>.private_key |
Path to the SSH private key file |
BACKUP_SFTP_PASSPHRASE |
targets.<name>.passphrase |
Passphrase for the private key |
BACKUP_SFTP_ROOT |
targets.<name>.root |
Remote directory backups are written into |
Commands
Cron
Schedule backup/run from your crontab. The example below runs it every night at 3 AM — use crontab.guru to tweak the cadence if you want a different schedule.
Monitoring
Taking a backup doesn't mean much if nobody notices when it silently stops working. backup/monitor evaluates the rules under monitor_backups in config/backup.php and prints a JSON report, exiting non-zero on failure so it's easy to wire into external health checks.
Each rule asserts one or more conditions against a named target:
Both min_number_of_backups and youngest_backup_should_be_within_the_last are optional; omit either to skip that assertion. The target key is required and must match an entry under targets. You can repeat the same target across multiple rules if you want each assertion reported separately.
Sample output on success:
And on failure:
With Oh Dear
If you already use Oh Dear for uptime monitoring, our craft-ohdear plugin exposes a Check::backupHealth() check that wraps backup/monitor — Oh Dear will then alert you (email, Slack, etc.) the moment a backup assertion fails, without you needing a separate cron-to-pager pipeline.
Yet another backup plugin? Here's why:
At webhub we've been building on Craft CMS and Laravel for years, and we want backups to work the same way across every project — whether the site runs on Craft or Laravel. This plugin closes one more part of the gap between the two stacks, following our Craft Oh Dear and Flare plugins. On Laravel projects we reach for Spatie's excellent laravel-backup without a second thought; we wanted the same reliable, boring-in-a-good-way experience on Craft. And with Craft 5 (Yii-based) and Craft 6 (Laravel-based) both in the community's future, every Craft developer will soon be maintaining projects on both stacks — a backup tool that behaves consistently across all of them matters.
Compared to spatie/laravel-backup
This plugin deliberately mirrors the CLI surface and config shape of spatie/laravel-backup so Laravel developers coming to Craft land on familiar ground.
webhubworks/craft-backup |
spatie/laravel-backup |
|---|---|
craft backup/run |
artisan backup:run |
craft backup/run --only-db |
artisan backup:run --only-db |
craft backup/run --only-files |
artisan backup:run --only-files |
craft backup/run --only-to=offsite |
artisan backup:run --only-to-disk=s3 |
craft backup/list |
artisan backup:list |
craft backup/clean |
artisan backup:clean |
config/backup.php |
config/backup.php |
local + sftp targets (more drivers planned) |
Filesystem "disks" as targets |
| ✅ | Database and file backup support |
| ✅ | Encryption support |
| ✅ | GFS retention |
| ✅ | Mail notifications |
| ✅ | Slack notifications |
✅ (via backup/monitor + Oh Dear integration) |
Monitor the health of your backups |
| Coming soon | Discord notifications, Webhooks |
What is GFS retention? And why should I care?
GFS stands for Grandfather-Father-Son, a classic rotation scheme from the days of tape backups. The idea: you keep lots of very recent backups, some weekly ones, and a few monthly and yearly ones. Older backups automatically get thinner on the ground instead of piling up forever.
Why bother? Two very practical reasons:
- Disk/SFTP quota. Running a nightly backup and keeping them all means a year's worth of full-site archives sitting on your storage. GFS caps that without you having to remember to clean up.
- Recovery granularity that matches how bugs are actually discovered. You almost always need "yesterday" or "last week" — fine-grained, recent snapshots. Occasionally you need "last month" when a slow data corruption finally surfaces. Very rarely you need "a year ago" for a long-running legal/accounting question. GFS gives you all three without storing hundreds of archives.
Advanced configuration
Archive format
Pick the container via compression.format:
| Format | Output filename | Encryption option |
|---|---|---|
zip (default) |
<name>-<ts>-<runid>.zip |
compression.password, AES-256 |
tar.gz |
<name>-<ts>-<runid>.tar.gz[.enc] |
encryption block, AES-256-CBC + HMAC-SHA256 |
zip is the default because it can be opened with any standard archive tool. tar.gz compresses better and pairs with the bundled authenticated-envelope encryption if you want integrity verification on top.
Encryption & restore
Encryption is off by default — a plain .zip comes out of a run until you configure a password (for zip) or enable the custom envelope (for tar.gz). Two modes:
zip + password (default format)
Set a password in .env:
The shipped config/backup.php already reads this via App::env(). Decrypt:
tar.gz + encryption block
Use this when you want authenticated encryption (tampering/truncation fails closed on decrypt) or better compression. The file extension becomes .tar.gz.enc and standard tools like openssl enc or gpg cannot open it — you decrypt with the bundled command or the standalone script.
Generate a 32-byte base64 key once and store it somewhere you will not lose it (password manager, sealed envelope, team vault):
Switch formats and enable encryption in .env:
Also set compression.format to tar.gz in config/backup.php (or leave it default once you flip the plugin default). Lose the key and the archive is unrecoverable — by design.
Decrypt:
scripts/decrypt.php is intentionally dependency-free — copy it onto any recovery machine alongside the archive and the base64 key.
Restoring the contents
Both formats, once extracted, produce a db-db.sql at the root plus a files/ tree mirroring your configured source.include paths (relative to @root). Import the SQL with your DB's native tool (mysql < db-db.sql, psql -f db-db.sql, etc.) and drop the files back into place.
Changelog
See the changelog for release history.
Security
See SECURITY.md for our security policy and instructions on how to report a vulnerability.
Credits
- Spatie for the inspiration and the Laravel version of this plugin.
- Marven Thieme
License
The MIT License (MIT). Please see License File for more information.
All versions of craft-backup with dependencies
craftcms/cms Version ^4.4.0 || ^5.0.0
league/flysystem-sftp-v3 Version ^3.0
phpseclib/phpseclib Version ^3.0.51