This installs root-run backup jobs for Enhance servers. The database job
discovers WordPress sites under /var/www, dumps each local MariaDB database
through socket-auth root access, uploads a plain .tar.gz archive to Backblaze
B2 with rclone's native B2 backend, and removes the local archive only after
remote verification succeeds.
The files job reuses the same rclone credentials, archives each site's
public_html contents, preserves modes, mtimes, ACLs, and xattrs, excludes
common local backup/archive files, uploads to B2, verifies the remote object,
and removes the local archive only after verification succeeds.
One command sets up both the database and files backups. Straight from GitHub:
sudo bash -c "$(curl -fsSL https://raw.githubusercontent.com/wnstify/backup-enhance/main/install.sh)"This fetches both runners and the shared library into a temp directory and walks you through setup. Prompts read from the terminal, so the command stays interactive. Or, from a clone of this repo:
sudo ./install.shThe installer asks for:
- Backblaze application key ID and application key
- Backblaze bucket name
- Database backup folder inside the bucket, for example
database-backups/server-name /var/wwwscan path, temp directory, archive date format, name mode, and database retention days- File backup rclone target (defaults to the database target with
database-backupsswapped forfile-backups), files retention, verify mode, and archive layout - Optional systemd timer schedules for the database and files jobs
Use a restricted Backblaze application key scoped to the backup bucket.
Re-running the installer upgrades an existing server in place: it detects the
stored B2 key and offers to keep it (so you do not re-enter credentials), and
prefills every prompt from the current /etc/enhance-db-backup/env. The default
files target is derived from the database target:
b2:BUCKET/database-backups/server-name -> b2:BUCKET/file-backups/server-name
The default database archive name format is:
testing1_25-5-26_18-00.tar.gz
The default files archive name format is:
testing1_files_25-5-26_18-00.tar.gz
By default file archives use FILES_BACKUP_ARCHIVE_LAYOUT=contents. The archive
contains the contents of public_html, not a top-level public_html directory,
so a website SSH user can extract it from inside the existing public_html.
By default testing1.com becomes testing1. Set this in
/etc/enhance-db-backup/env if you prefer full domains:
BACKUP_NAME_MODE=full-domainWith full-domain, testing1.com becomes testing1.com_25-5-26_18-00.tar.gz.
The installers accept either a preset number or a custom systemd OnCalendar
value.
Database timer presets:
1) Hourly: *-*-* *:00:00
2) Every 2 hours: *-*-* 00/2:00:00
3) Every 3 hours: *-*-* 00/3:00:00
4) Every 6 hours: *-*-* 00/6:00:00
5) Twice daily: *-*-* 02,14:30:00
6) Daily default: *-*-* 02:30:00
Files timer presets:
1) Daily: *-*-* 03:00:00
2) Every 3 days: *-*-01/3 04:00:00
3) Weekly: Sun *-*-* 04:00:00
4) Every 10 days: *-*-01/10 04:00:00
5) Every 14 days: *-*-01/14 04:00:00
6) Monthly: *-*-01 04:00:00
- Database dumps use MariaDB root socket auth, so app database passwords are not copied into backup config.
- Secrets live in
/etc/enhance-db-backup/rclone.conf, owned byroot:root, mode600. - Runtime settings live in
/etc/enhance-db-backup/env, owned byroot:root, mode600. - Temporary files are created under a mode
700working directory. - A
.tar.gzis written into a root-only temporary directory, uploaded with rclone, verified, and deleted only after verification succeeds. - Uploads are retried with
BACKUP_UPLOAD_RETRIES,BACKUP_UPLOAD_RETRY_DELAY, and rclone low-level retries. - If all upload or verification attempts fail, the unverified archive is moved
to
BACKUP_FAILED_DIR, which defaults to/var/tmp/enhance-db-backup/failed. BACKUP_VERIFY_MODE=sizeverifies that the remote object exists and matches the local archive size.BACKUP_VERIFY_MODE=deepdownloads the archive and validates the tar/gzip stream, but doubles transfer for each backup.BACKUP_LOCK_MODE=autouses non-blocking--single-transactiondumps for all-InnoDB databases and switches to--lock-tablesonly when a database has non-transactional tables.- Remote retention uses
BACKUP_RETENTION_DAYS;0disables automatic remote deletion. - The
[b2]remote setshard_delete = trueand the prune passes--b2-hard-delete, so retention permanently removes old object versions. On a versioned bucket without this,rclone deleteonly writes a hide-marker and every "deleted" archive keeps billing forever. - File backups use
FILES_BACKUP_RCLONE_TARGET,FILES_BACKUP_RETENTION_DAYS,FILES_BACKUP_VERIFY_MODE, andFILES_BACKUP_ARCHIVE_LAYOUT. - For customer self-restore, keep the existing
public_htmldirectory in place and extract the archive inside it as the website SSH user. - For root-level restores from the parent site directory, set
FILES_BACKUP_ARCHIVE_LAYOUT=public_html.
Dry-run discovery:
sudo enhance-db-backup --dry-runRun a backup:
sudo enhance-db-backupList remote archives:
sudo bash -c 'set -a; . /etc/enhance-db-backup/env; set +a; rclone --config "$BACKUP_RCLONE_CONFIG" lsf "$BACKUP_RCLONE_TARGET"'Systemd timer:
systemctl status enhance-db-backup.timer
journalctl -u enhance-db-backup.serviceDry-run discovery:
sudo enhance-files-backup --dry-runRun a backup:
sudo enhance-files-backupList remote file archives:
sudo bash -c 'set -a; . /etc/enhance-db-backup/env; set +a; rclone --config "$BACKUP_RCLONE_CONFIG" lsf "$FILES_BACKUP_RCLONE_TARGET"'Systemd timer:
systemctl status enhance-files-backup.timer
journalctl -u enhance-files-backup.serviceIf file backups upload only the first few sites and then stop, check for a systemd timeout, live files changing during tar, or local plugin backup files:
journalctl -u enhance-files-backup.service --since todayFix an already-installed server:
sudo sed -i '/^ExecStart=/a TimeoutStartSec=0' /etc/systemd/system/enhance-files-backup.service
sudo systemctl daemon-reload
sudo systemctl restart enhance-files-backup.timerIf logs show file changed as we read it or local .wpress archives are being
included, update the installed runners from the latest repo version by
re-running the installer. It inlines the shared library into each runner,
syntax-checks the assembled result, and reinstalls it:
sudo ./install.shRe-running is a safe in-place upgrade: it keeps your stored B2 key and prefills
every prompt from the current /etc/enhance-db-backup/env. Installing a runner
by hand no longer works, because each runner sources enhance-backup-lib.sh,
which the installer inlines; only install.sh produces a standalone runner.
New installs include these settings automatically.
On a server installed before hard-delete, add hard_delete = true under [b2]
in /etc/enhance-db-backup/rclone.conf, reinstall the runners from this repo,
then reap the hidden version backlog once (live 7-day window untouched):
sudo bash -c 'set -a; . /etc/enhance-db-backup/env; set +a; \
rclone --config "$BACKUP_RCLONE_CONFIG" cleanup "$BACKUP_RCLONE_TARGET"; \
rclone --config "$BACKUP_RCLONE_CONFIG" cleanup "$FILES_BACKUP_RCLONE_TARGET"'Use db-restore.md for database restores and files-restore.md for
owner-preserving WordPress file restores.