@black-magic/craft-maintenance
v0.0.8
Published
CLI tool to backup and update Craft CMS sites on SiteGround
Keywords
Readme
craft-site-maintenance
CLI tool to automate Craft CMS maintenance on SiteGround-hosted sites. Connects via SSH, creates backups (DB + config + composer files), updates plugins one by one, downloads a local copy of the backup, and automatically rolls back on failure.
Installation
# Run without installing
pnpm dlx @black-magic/craft-maintenance
# Or install globally
pnpm add -g @black-magic/craft-maintenanceSetup
Create a .craft-maintenance.json file in the directory where you'll run the command, or in ~/ for global use:
{
"localBackupDir": "~/craft-backups",
"sites": [
{
"sshAlias": "blackmagic",
"siteDir": "example.com",
"phpBin": "php82"
}
]
}localBackupDir is optional — defaults to ~/craft-backups. Backups are saved as {localBackupDir}/{siteDir}/{timestamp}.tar.gz.
You can also specify a config file explicitly:
craft-maintenance --config /path/to/config.jsonSSH connection options
There are two ways to specify the SSH connection for each site:
Option A — SSH config alias (recommended)
If the site is already in your ~/.ssh/config, reference the alias directly:
{
sshAlias: "blackmagic", // Host entry in ~/.ssh/config
siteDir: "example.com", // directory under ~/www/ on the server
phpBin: "php82",
}~/.ssh/config entry:
Host blackmagic
HostName ssh.example.siteground.com
User u1234-abc12def34gh
Port 18765
IdentityFile ~/.ssh/id_rsa_sitegroundIf IdentityFile is omitted, the SSH agent (SSH_AUTH_SOCK) is used automatically.
Option B — explicit credentials
{
ssh: {
host: "ssh.example.siteground.com",
username: "u1234-abc12def34gh",
port: 18765,
privateKeyPath: "~/.ssh/id_rsa_siteground",
},
siteDir: "example.com",
phpBin: "php82",
}Usage
craft-maintenance # interactive update
craft-maintenance --dry-run # preview pending updates without making changes
craft-maintenance --status # check last run status for all configured sites
craft-maintenance --config /path/to/config.jsonDuring development:
pnpm dev
pnpm dev -- --dry-run
pnpm dev -- --statusNormal mode
- Select which sites to update (multi-select)
- Confirm
- For each site, sequentially:
- Shows working directory on the remote server
- Creates a timestamped backup: DB,
config/,composer.json,composer.lock - Compresses the backup and downloads it locally via SCP
- Deletes the remote backup folder (only after successful download)
- Updates each plugin individually with
craft update {handle} - On failure: automatically rolls back to the pre-update state
- Shows a summary with local backup path per site
Dry-run mode (--dry-run)
Connects via SSH and runs craft update to list pending plugin/package updates — without making any changes or requiring confirmation.
Status mode (--status)
Connects to each configured site and reads .craft-maintenance-status.json to show the result of the last maintenance run. No changes are made.
✓ example.com success 2026-04-02 14:30 craft/cms 5.1→5.2
⚠ other.com failed_update 2026-03-28 09:12 Failed on: feed-me
✗ broken.com failed_rollback 2026-03-15 09:12 ← REQUIRES MANUAL INTERVENTION
– new.com never runWhat gets backed up
Before any update, the tool creates a backup on the remote server at $HOME/www/{siteDir}/.craft-backups/{timestamp}/:
| File | Description |
|------|-------------|
| db-backup.sql | Full database dump via craft db/backup |
| config/ | Copy of the entire config/ directory |
| composer.json | Composer manifest |
| composer.lock | Locked dependency versions |
The backup folder is then compressed into a .tar.gz and downloaded to your local machine at {localBackupDir}/{siteDir}/{timestamp}.tar.gz. The remote folder is deleted after a successful download — if the download fails, the remote copy is kept.
After a successful run, each site also has a status file at $HOME/www/{siteDir}/.craft-maintenance-status.json with the result of the last operation.
Auto-rollback
If any plugin update fails, the tool immediately runs a rollback:
- Restore
composer.json+composer.lockfrom backup - Run
composer install --no-interactionto restorevendor/ - Restore
config/from backup - Restore the database via
craft db/restore
The final summary distinguishes three states:
| State | Meaning | |-------|---------| | ✓ Updated | Update succeeded | | ⚠ Rolled back | Update failed, site restored to pre-update state | | ✗ Critical | Update failed and rollback also failed — manual intervention required |
Build
pnpm build # Compiles to dist/index.js (ESM bundle)Commit conventions
This project uses Conventional Commits, enforced via commitlint on every commit:
feat: add dry-run flag
fix: handle SSH timeout gracefully
chore: update dependenciesTo regenerate CHANGELOG.md from commit history:
pnpm changelog # from last tag to HEAD
pnpm changelog:all # entire history
pnpm changelog v1.0.0 # from a specific tagSiteGround SSH notes
- SSH port is
18765, not22 - Home directory:
/home/{username}/, sites under/home/{username}/www/{domain}/ - PHP binaries:
php82,php83(notphporphp-cli) - Craft executable:
$HOME/www/{domain}/craft - Docroot:
public_html/(notweb/)
