Backups and History
Restic backups, git-based quicksaves, downloadable snapshots, archives, visual captures and update logs.
CaptainCore keeps four separate kinds of history per site environment: Restic backups of files and database, git-based quicksaves of the plugin and theme tree, zipped snapshots for download, and visual captures of rendered pages. Update logs tie a pair of quicksaves together to describe what an update run changed.
Storage layout
Backups are written with Restic through an Rclone backend. The repository path for a site environment is:
rclone:<rclone_backup>/<site>_<site_id>/<environment>/restic-repo
Quicksaves use a sibling repo at quicksave-repo, and archived server logs land in a logs folder next to them. The Restic password comes from ~/.captaincore/data/restic.key. Long-running repo operations set TMPDIR from the system path_tmp value, because repacking a large repo needs hundreds of gigabytes of scratch space.
Restic is invoked with an explicit rclone serve line so B2 deletes are hard deletes and the timeouts are generous:
restic ... -o "rclone.args=serve restic --stdio --b2-hard-delete --timeout=300s --contimeout=60s" -o rclone.timeout=600s
Remotes read from config.json
The system block supplies paths and default remotes; the per-captain block can override them.
| Config key | Block | Used for |
|---|---|---|
rclone_backup |
system or captain remotes |
Restic backup and quicksave repos, and archived logs |
rclone_snapshot |
system | Destination for generated snapshot zips |
b2_snapshots |
captain remotes |
B2 bucket for snapshot links. Derived from rclone_snapshot when unset |
rclone_archive |
captain remotes |
Archive listing, sharing and cold storage |
rclone_logs |
captain remotes |
Log storage |
rclone_upload |
system or captain remotes |
Upload remote for generated files and thumbnails |
path |
system | Local site data path, <path>/<site>_<site_id>/<environment>/ |
path_tmp |
system | TMPDIR for repo migrations and prune |
logs |
system | Local log output path |
The captain remotes.rclone_backup wins over the system rclone_backup. In fleet mode the captain ID is appended to the backup remote and to the local site path, so tenants never share a repo.
The excludes files
Two exclusion lists ship in lib/.
lib/excludesis passed torclone syncas--exclude-fromwhen files are pulled down from the site. It skipserror_log,/tmp,.DS_Store,node_modules/, the localdatabase-backup.sql, and the backup and cache directories of the common backup plugins: UpdraftPlus, All-in-One WP Migration, Duplicator, BackWPup, BackupBuddy, Akeeba, Envato, Divi’set-cacheandet_temp, WP Super Cache and friends.lib/restic-excludesis passed torestic backupas--exclude-file. It covers the same plugin backup and cache directories, plusdebug.log,error_logandphperror_log.
backup
captaincore backup <subcommand> <site>
Everyday use
| Subcommand | Usage |
|---|---|
generate |
backup generate <site> [--parallel=] [--skip-db] [--skip-remote] [--skip-if-recent=] [--dry-run] |
list |
backup list <site> [--format=json] |
list-generate |
backup list-generate <site> [--from-file=] |
list-missing |
backup list-missing <site> |
snapshots |
backup snapshots <site> [snapshot-id] [--sizes] [--format=json] |
download |
backup download <site> <backup-id> [<payload>] [--payload=] [--email=] |
get |
backup get <site> <backup-id> |
get-generate |
backup get-generate <site> <backup-id> |
show |
backup show <site> <backup-id> <file-id> |
find |
backup find <site> <pattern> [--long] [--pack=] [--snapshot=] |
fetch-link |
backup fetch-link --site= --site-id= --zip-name= |
runtime |
backup runtime <site> |
verify |
backup verify <site> [--from-file=] |
repo-info |
backup repo-info <site> [--stats] |
backup generate defaults to -p, --parallel 3. --skip-if-recent=24h skips an environment backed up within that window, which is what makes a nightly @all run cheap to re-run.
captaincore backup generate @all --parallel=5 --skip-if-recent=20h
--payload on backup download names a token identifying which files and directories to include. The captaincore server writes large payload blobs to ~/.captaincore/data/payload/<token>.txt and passes the token on the command line rather than the blob.
Repository maintenance
| Subcommand | Usage |
|---|---|
check |
backup check <site> [--init] [--read-data] |
prune |
backup prune <site> [--dry-run] [--repack-uncompressed] |
forget |
backup forget <site> <snapshot-id> [--confirm] [--prune] |
unlock |
backup unlock <site> [--remove-all] |
repair |
backup repair <site> [pack-ids...] [--packs] [--snapshots] [--forget] |
upgrade |
backup upgrade <site> |
migrate-v2 |
backup migrate-v2 <site> [--force] [--skip-repack] [--skip-cache-cleanup] |
key-backup |
backup key-backup <site> [--type=backup|quicksave] |
key-restore |
backup key-restore <site> [--type=backup|quicksave] |
cleanup |
backup cleanup <site> [--dry-run] |
storage-cleanup |
backup storage-cleanup [--confirm] |
backup migrate-v2 is the orchestrated version-1 to version-2 migration: it checks whether the repo is already v2, runs restic migrate upgrade_repo_v2, repacks uncompressed data with restic prune --repack-uncompressed, clears the remote Restic cache over SSH, then verifies the final state.
backup key-backup copies the Restic repo key out of B2 to a local backup-repo-key.txt (or quicksave-repo-key.txt) so a B2 data loss does not cost you the repo. key-restore puts it back.
backup forget and backup storage-cleanup preview by default; --confirm is required to actually delete.
captaincore backup check mysite-production --read-data
quicksave
Quicksaves are per-site git repositories tracking plugin, theme and configuration changes, with the git repo itself backed up into Restic.
| Subcommand | Usage |
|---|---|
generate |
quicksave generate <site> [--force] [--parallel=] [--skip-if-recent=] [--dry-run] [--debug] |
add |
quicksave add <site> [--force] |
list |
quicksave list <site> [--field=] |
latest |
quicksave latest <site> [--field=] |
list-generate |
quicksave list-generate <site> |
list-missing |
quicksave list-missing <site> |
get |
quicksave get <site> <hash> |
get-generate |
quicksave get-generate <site> <hash> |
show-changes |
quicksave show-changes <site> <commit-hash> [<match>] |
file-diff |
quicksave file-diff <site> <commit> <file> [--plugin=] [--theme=] [--html] |
search |
quicksave search <site> <theme|plugin:title|name:search> |
rollback |
quicksave rollback <site> <commit> [--plugin=] [--theme=] [--file=] [--all] [--version=this|previous] |
archive |
quicksave archive <site> <hash> [--plugin=] [--theme=] |
database |
quicksave database <site> <hash> |
malware-scan |
quicksave malware-scan <site> [--full] [--format=json] [--label] |
backup |
quicksave backup <site> [--parallel=] [--skip-if-recent=] |
restore-git |
quicksave restore-git <site> |
sync |
quicksave sync <site> |
update-usage |
quicksave update-usage <site> |
cache-check |
quicksave cache-check <site> [--format=json] |
cache-purge |
quicksave cache-purge <site> [--dry-run] |
unlock |
quicksave unlock <site> |
migrate-v2 |
quicksave migrate-v2 <site> [--force] [--skip-repack] [--skip-cache-cleanup] |
quicksave database extracts and sanitizes the database SQL from the nearest backup snapshot for a given quicksave, which is how a quicksave can be paired with the data of its moment. quicksave malware-scan --full runs a Wordfence CLI scan over the whole quicksave directory rather than the signature list.
captaincore quicksave generate @all --parallel=10 --skip-if-recent=24h
snapshot
Snapshots are one-off downloadable zips, distinct from Restic snapshots.
| Subcommand | Usage |
|---|---|
generate |
snapshot generate <site> [--email=] [--notes=] [--filter=] [--user-id=] [--skip-remote] [--delete-after-snapshot] |
list |
snapshot list <site-id> [--environment=] [--limit=] [--field=] [--format=json] |
add |
snapshot add --site-id= --archive= --storage= [--environment=] [--email=] [--notes=] [--user-id=] |
fetch-link |
snapshot fetch-link <snapshot-id> |
--filter takes one or more of database, themes, plugins, uploads, everything-else. Without a filter the snapshot includes everything. --delete-after-snapshot deletes the site after the final snapshot is made. The generated zip is moved to the rclone_snapshot remote unless --skip-remote is given.
captaincore snapshot generate mysite-production --filter=database,themes,plugins [email protected]
store-snapshot
captaincore store-snapshot <url|file>
Moves a zip to the rclone_archive remote for cold storage.
captaincore store-snapshot https://example.com/mysite-2026-09-04.zip
archive
captaincore archive list
captaincore archive share <file>
archive list runs rclone lsjson against rclone_archive. archive share runs rclone link with --expire 168h, so the public link lasts seven days.
captaincore archive share mysite-2026-09-04.zip
capture
Captures render the site’s pages and store the HTML and screenshots, so injected scripts can be detected by comparison over time.
| Subcommand | Usage |
|---|---|
generate |
`capture generate <site |
scan |
capture scan <site|@target> [--filter=] [--format=json] [--malware] |
check |
capture check <site> |
--pages overrides the pages to check, otherwise the site’s stored capture_pages configuration is used. capture scan --filter accepts critical, warning or external; --malware narrows to scripts only and hides ok results. Signatures come from lib/capture-signatures.json.
captaincore capture scan @production --malware --format=json
update-log
An update log describes what changed between a pair of quicksaves.
| Subcommand | Usage |
|---|---|
generate |
update-log generate <site> <quicksave-hash-before> <quicksave-hash-after> |
get |
update-log get <site> <quicksave-hash-before> <quicksave-hash-after> |
list |
update-log list <site> |
list-generate |
update-log list-generate <site> |
captaincore update-log list mysite-production
Archived server logs
Rotated access and error logs are streamed to B2 alongside the backup repos. See monitoring and health for logs archive, logs archive-list and logs archive-get.