BackupRidge

Description

BackupRidge is a WordPress backup plugin designed for reliability on every host. Full-site backups pause and resume across requests, so they complete even on shared hosting with strict time limits. Back up to local storage or remote providers, restore from any source, migrate another WordPress site into this one, and monitor everything from a clean admin dashboard.

Standard Features

  • Resumable backups — Long-running backups save progress and resume from the last checkpoint so they finish on any host, including shared hosting with 30-second limits.
  • Database backup — MySQL/MariaDB export via mysqldump (when available) or native PHP streaming with optional table filtering and row-level resumption.
  • File backup — Back up wp-content (and optionally the full WordPress root) with exclusion patterns, compression, and optional archive splitting for large sites.
  • Local storage — Store completed backups on the server filesystem. Optional subfolder under uploads (base: wp-content/uploads/backupridge).
  • Remote storage — Add multiple destinations and upload completed backups to Amazon S3, Cloudflare R2, FTP, or SFTP.
  • Scheduled backups — Run backups automatically on a daily, weekly, or custom schedule via WP-Cron, with a REST endpoint available for triggering from an external system cron.
  • Restore — Restore from a local backup, remote storage, or an uploaded archive, with component-level selection (database, themes, plugins, uploads, core) so you only restore what you need.
  • Site migration (receive) — Migrate another WordPress site into this one by uploading a BackupRidge migration archive from the Migrate admin page.
  • Dashboard — View backup status, history, progress, and logs. Start, stop, continue, or retry backups from the admin UI.
  • Backup watchdog — A cron-based watchdog recovers backups that stall due to missed cron events or loopback failures.
  • Custom backup filenames — Choose a filename prefix (BackupRidge, site URL, or site name) with automatic date/time stamping.
  • Multi-part downloads — Download each archive part from the dashboard, or use Download All to queue sequential direct downloads (reliable on shared hosting).
  • Log viewer — Browse and download per-job log files directly from the admin UI.
  • Webhook notifications — Optional HTTP POST after a successful and/or failed backup (you choose): generic JSON, Slack incoming webhook, or Discord webhook format; URL, format, and which outcomes to notify are in Settings.
  • Update-screen warning — See a notice on WordPress update screens when no backup has been created in the last 24 hours.

Advanced Features

  • More cloud providers + OAuth — Connect Google Drive, Dropbox, OneDrive, and Backblaze B2 with easy OAuth sign-in—no manual API keys required.
  • Incremental backups — Only back up files that changed since the last run, reducing time and storage.
  • Archive encryption — AES-256-GCM authenticated encryption for backup archives before upload (legacy AES-256-CBC archives are still decryptable for restore).
  • Advanced scheduling — Multiple independent schedules with time-of-day, day-of-week, 5-field cron expression support, and per-schedule settings overrides.
  • Backup verification — SHA-256 integrity checks on every archive part after backup completes.
  • System cron integration — Managed system cron setup and WP-CLI commands for triggering and automating backups, instead of relying on WP-Cron.
  • Custom filename templates — Build filenames from placeholders ({type}, {seq}, and more) instead of a fixed prefix.

Requirements

PHP 8.0 or higher, WordPress 6.7 or higher. The backup directory (default wp-content/uploads/backupridge) must be writable by the web server.

External services

BackupRidge can upload backup archives to third-party cloud storage services configured by the user. No data is sent to any external service unless the user explicitly configures a storage provider.
Links to backupridge.com and stavatech.no are informational website links and do not receive backup data from the plugin.

Amazon S3

Used to store backup archives via the S3 API. Signed requests with user-provided credentials and backup files are transmitted when the user configures S3 storage.
* AWS Customer Agreement
* AWS Privacy Notice

Cloudflare R2

Used to store backup archives via S3-compatible API calls. Signed requests with user-provided credentials and backup files are transmitted when the user configures R2 storage.
* Cloudflare Terms
* Cloudflare Privacy Policy

FTP

Used to upload backup archives to a host, port, and credentials supplied by the site administrator. Data is transmitted only when the user configures FTP storage.
This connection targets a user-selected server endpoint (self-hosted or third-party chosen by the site owner), so no single provider Terms or Privacy policy applies.

SFTP

Used to upload backup archives over SSH file transfer to a host, port, and credentials (or key) supplied by the site administrator. Data is transmitted only when the user configures SFTP storage.
This connection targets a user-selected server endpoint (self-hosted or third-party chosen by the site owner), so no single provider Terms or Privacy policy applies.

Google Drive (BackupRidge Advanced only)

Not included in the WordPress download. When installed separately, BackupRidge Advanced can upload backups via the Google Drive API using OAuth and user-granted access. Backup file data and metadata needed for the upload are sent to Google when the user configures this provider and runs a backup. Setup requires enabling the Google Drive API on your Google Cloud project (not only OAuth credentials). See https://backupridge.com/docs/cloud-storage#google-drive

Dropbox (BackupRidge Advanced only)

Not included in the WordPress download. When installed separately, BackupRidge Advanced can upload backups via the Dropbox API using OAuth. Backup file data is sent to Dropbox when the user configures this provider and runs a backup. Setup requires enabling file permissions on your Dropbox app and clicking Submit in the Permissions tab before OAuth. See https://backupridge.com/docs/cloud-storage#dropbox

Microsoft OneDrive (BackupRidge Advanced only)

Not included in the WordPress download. When installed separately, BackupRidge Advanced can upload backups via Microsoft Graph / OneDrive using OAuth. Backup file data is sent to Microsoft when the user configures this provider and runs a backup. Setup requires an Azure app registration with a redirect URI of wp-admin/admin.php (no query string) and account types matching your Microsoft sign-in. See https://backupridge.com/docs/cloud-storage#onedrive

Backblaze B2 (BackupRidge Advanced only)

Not included in the WordPress download. When installed separately, BackupRidge Advanced can upload backups to Backblaze B2 via the Backblaze B2 Native API. It calls https://api.backblazeb2.com to authorize the session with the user-provided Key ID and Application Key, then uploads the backup archive parts. Backup file data is sent to Backblaze only when the user configures this provider and runs a backup.

HTTP webhooks (backup status)

When webhooks are enabled in Settings, the plugin can send an HTTP POST to the URL you provide after a backup succeeds and/or after it fails, depending on the checkboxes you set. Choices: generic JSON (job id, status, size, duration, timestamp), Slack incoming webhook (JSON with a text field), or Discord webhook (JSON with a content field). Data is sent only to your URL; the receiving service’s terms apply if you use Slack or Discord.

REST / cron trigger (this plugin)

Optional: a REST URL with a secret key can be called by system cron so the site can run backup segments without WP-Cron or loopback. Requests go only to the same WordPress site; no third party receives data unless the site owner configures something else.

Preferred authentication: send the key in the X-BackupRidge-Cron-Key request header. Legacy ?key= query authentication remains supported for compatibility, but query strings can be logged by proxies and web servers.

Source Code

This plugin ships its full, human-readable source. Every minified script in assets/js/dist/ has its un-minified source in assets/js/src/, and the minified stylesheet assets/css/admin.min.css has its source in assets/css/admin.css, inside the same plugin package, so each compiled file can be reviewed and rebuilt. No source is removed during packaging.

Build tools and steps to regenerate the compiled assets:

  • Requirements: Node.js 18+ and npm.
  • Install dependencies: npm install
  • Build JS and CSS (terser minifies each assets/js/src/*.js into assets/js/dist/, and PostCSS/cssnano minifies assets/css/admin.css into assets/css/admin.min.css): npm run build

PHP dependencies are managed with Composer (composer install). No third-party JavaScript libraries are bundled in a minified-only form; all shipped scripts are first-party and their sources are included as described above.

Screenshots

Installation

  1. Upload the plugin zip via Plugins Add New Upload, or install from the WordPress plugin directory.
  2. Activate the plugin through the Plugins screen.
  3. Go to BackupRidge in the admin menu to configure settings, storage, and schedules.
  4. Use the Dashboard to start a manual backup or view history and logs.

For first-time setup, ensure the backup directory (Settings Backup directory) is writable. The plugin creates wp-content/uploads/backupridge by default for backups, logs, and temporary files.

FAQ

Where are backups stored?

By default, backups are stored in wp-content/uploads/backupridge/backups. In Settings, you can optionally set a subfolder under wp-content/uploads/backupridge/ (for example staging/site-a), but absolute custom paths are not allowed. You can also configure remote storage (S3, R2, FTP, SFTP, and more with Advanced) to upload completed backups off-site.

Can I resume a backup if it stops?

Yes. BackupRidge saves progress at regular checkpoints and can resume from the last one. If a backup stalls, click “Continue” on the Dashboard to pick up where it left off. A built-in watchdog also detects stalled backups and re-schedules them automatically.

What happens if WP-Cron is unreliable on my host?

BackupRidge has several fallback mechanisms: a loopback self-call, a cron trigger REST endpoint for system cron, and the ability to run a backup segment during the dashboard status poll. Even on hosts where WP-Cron is disabled or unreliable, backups can make progress whenever someone visits the admin.

Can I restore specific parts of a backup?

Yes. The restore dialog lets you choose which components to restore: database, themes, plugins, uploads, and/or core files. You can optionally save a safety copy of the current database on the server before starting (recommended for large sites only if you accept the extra time).

Can I migrate a site to this one?

Yes. From the Migrate admin page, upload a BackupRidge migration archive exported from another site and BackupRidge assembles and restores it here. This receiving side is Standard. Pushing a migration directly from one BackupRidge install to another (including staging clones) is a Advanced feature.

How does archive splitting work?

When a backup exceeds the configured maximum archive size, BackupRidge splits it into multiple numbered parts (e.g. backup_001.zip, backup_002.zip). All parts are uploaded to remote storage and can be downloaded individually or all at once via Download All (sequential direct downloads).

Import Backup is slow or fails with larger upload chunks. What should I change?

Import Backup uploads use chunked admin-ajax requests. Larger chunks reduce request overhead and are often faster, but each chunk must fit PHP limits.

BackupRidge automatically detects and applies a safe max chunk size from:

  • upload_max_filesize
  • post_max_size (minus multipart form overhead)

If uploads fail above a certain chunk size (for example above 8 MB), increase PHP limits so they are above your target:

  • upload_max_filesize = 16M
  • post_max_size = 24M

Then set Settings Upload Upload chunk size to a value below those limits (8 MB in this example). Keep post_max_size higher than upload_max_filesize.

What WordPress and PHP versions are supported?

WordPress 6.7 or higher and PHP 8.0 or higher. The plugin is tested on WordPress 6.8, 6.9, and 7.0 with PHP 8.0 through 8.3.

Is the backup directory protected from web access?

Yes. BackupRidge creates an .htaccess file and an index.php file in the backup directory to prevent direct web access on Apache and most hosting environments. For Nginx, add a location block to deny access to the backup directory.

What happens to my data if I uninstall the plugin?

Deleting BackupRidge from Plugins Installed Plugins removes its settings, scheduled cron events, and its backup storage directory (wp-content/uploads/backupridge), including any backup archives stored there. If you want to keep your backups, move or download them to another location, or switch to a remote storage destination, before deleting the plugin. Simply deactivating the plugin (without deleting it) leaves all settings and stored backups untouched.

Reviews

There are no reviews for this plugin.

Contributors & Developers

“BackupRidge” is open source software. The following people have contributed to this plugin.

Contributors

Translate “BackupRidge” into your language.

Interested in development?

Browse the code, check out the SVN repository, or subscribe to the development log by RSS.

Changelog

1.29.0

Major update: redesigned incremental backups, Advanced push migration & staging, safer restores, and license/security hardening.

  • New (Advanced): Direct push migration & staging — push a full site to another WordPress install with pre-flight checks, chunked resumable transfer, automatic URL search-replace, and a post-migration health check. Staging mode clones to a staging target behind a typed production-push confirmation.
  • New (Advanced): Incremental backups now use a differential model (delta since the last full/baseline) instead of a forward chain. A restore needs only two archives — the baseline plus the chosen differential — removing the old dependency on an unbroken chain of every prior run.
  • New: Each archive now embeds a self-describing file manifest (paths, hashes, baseline reference), so restores are deletion-correct and portable — an archive can be restored on a new site, or after a license lapse, without depending on stored site state. Restore remains a Standard feature.
  • New: Backup history now labels each backup as Full or Differential so you can identify the baseline at a glance.
  • Fix: Restoring a standalone differential without its baseline is now blocked with a clear explanation instead of silently producing an incomplete site.
  • Fix: Retention never prunes a baseline that a later differential still depends on, and manually deleting a depended-on baseline now requires confirmation.
  • Fix: Incremental change detection compares file size alongside modification time, so content changes that preserve the original mtime are no longer skipped. Incremental backups also re-baseline automatically on a configurable cadence.
  • New: Site migration now performs serialization-safe search-replace across plugin tables (not only core WordPress tables) on the destination.
  • Security: Hardened the migration chunk assembler against path traversal via unvalidated identifiers, confining all archive writes and deletes to the migration work area.
  • Security (Advanced): License plan tiers are now enforced, so a Personal license no longer unlocks Business-tier features. License validation adds a 14-day offline grace period so a license-server outage no longer disables Advanced features for paying customers, sends a site-ownership proof on license detail and transfer calls, and includes the license key when connecting cloud storage via Quick Connect.
  • Change: Clearer upgrade information — accurate plan names and pricing on the in-plugin upgrade screens, and the readme now documents site migration and the WP-Cron vs. system-cron scheduling split.
  • Fix: On a slow or contended host, a batch of many small files during file backup could go long enough without a heartbeat that a background watchdog started a duplicate resumption while the original was still running, silently dropping archive entries while the backup still reported success. The heartbeat now refreshes throughout the batch, not only once it finishes.
  • Fix: Uninstalling no longer leaves job-scheduled cron events behind.
  • Fix: Removed the “use custom database tables” setting, which never had a backing implementation.

1.28.8

  • Fix: On a Advanced install, the “Go Advanced” upgrade link in the page header kept showing even after successfully activating a license, and the header never showed a badge for the active plan. Advanced now shows an “Activate License” prompt only while unlicensed, and the plan’s badge once a license is active.

1.28.7

  • Fix: During restore, a brief window existed where a concurrent status check could see the source backup’s job as still “running” and start it again, overwriting the backup archive while it was being restored from. Restore now holds the source job’s lock for its full duration so this can’t happen.
  • Fix: A backup restored from a mysqldump-based export could resurrect and re-run its own source backup job, overwriting the original archive, because the exported database dump included the plugin’s own in-progress job data. Database exports now exclude this data, matching the existing PHP-export path.
  • Fix: A backup could run twice in a row and duplicate its database dump in the archive when two internal triggers (e.g. a manual start and a scheduled resumption check) raced to start the same job within the same second. The second trigger now always sees the job’s true up-to-date status instead of a stale cached copy.
  • Fix: Large-file backups could produce an oversized archive part exceeding the configured maximum size; the flush threshold is now capped by the space actually remaining in the current part.
  • Fix: Restores could appear frozen for 20+ seconds on modern hosts due to an overly conservative pause between each database table; the pause is now much shorter while remaining safe for older MySQL versions.
  • Fix: Backup log filenames now consistently match their corresponding archive filenames.
  • Change: Removed the plugin’s custom dark-mode styling, which only recolored the plugin’s own content area and looked inconsistent with the rest of the WordPress admin.

1.28.6

  • Fix: On slow hosts, a large backup could log “completed successfully” while actually storing nothing — the finished archive was lost when a background watchdog restarted the job during the final archive step (embedding the database and closing the archive). That final step is now reliable: it keeps the job alive while it runs, resumes correctly if interrupted, and — as a safety net — the backup now fails with a clear error instead of reporting success when no archive was produced. If you run large backups on a slow host, please run a fresh backup and confirm it completes with archives present.
  • Change: Per-component backup log lines now report each component’s full file count instead of only the files added in the final resumption segment, so the log accurately reflects how much was archived.

1.28.5

  • Fix: Backups containing a few very large files now split into properly-sized parts instead of one oversized part that could far exceed the configured maximum (and be rejected by storage providers with a per-file size limit). The time limit is also checked while those large files are added, so backups still pause and resume in time on slow hosts.
  • Change: Clearer backup logs — a missing optional mu-plugins directory is now logged as informational rather than an error, and a remote upload that continues across requests logs “Resuming provider” instead of “Starting provider”.

1.28.4

  • Fix: When a backup moves many large archive parts into local storage on a slow host, it now pauses and resumes cleanly between parts instead of risking a timeout part-way through the transfer.
  • Change: Clarified the “Resumption attempts” setting — it is now labelled a soft limit, with help text explaining that it never fails a backup on its own (a genuinely stuck backup is stopped automatically by stall detection).

1.28.3

  • Fix: On hosts that allow longer PHP execution, backups now run in fewer, longer segments instead of restarting roughly every 90 seconds. This cuts resumption overhead and the number of background hand-offs on large sites; total backup time is unchanged on restrictive hosts.
  • Fix: A backup that stops making progress is now detected and stopped with a clear error after several idle resumptions, instead of resuming indefinitely. This closes a gap where a stuck database-export or upload phase could loop forever.
  • Fix: Split archive parts no longer exceed the configured maximum part size. Previously a single batch of files could push a part well over the limit, which could cause a remote destination with a hard per-part size limit to reject the upload.
  • Change: The backup log is more diagnostic. It now warns (with the specific reason) when the slower pure-PHP archive method is used, and lists the largest subdirectories by file count in each component, making it easier to spot and exclude caches or other bloat that slow backups down.

1.28.2

  • Change: Backup downloads now run through WordPress’s standard request handling instead of a separate download script. This improves compatibility with hosts that block direct PHP execution under the uploads directory. Existing download links keep working; no action is required.
  • Security: Removed all directly-accessible standalone PHP files from the plugin and stopped writing any PHP into the uploads directory.

1.28.1

  • Fix: Dropbox uploads failed with a “not_found” error because the upload session id was parsed incorrectly, and files were written to a doubled “/backups/backups/” path. Both are resolved.
  • Fix: OneDrive and Google Drive uploads now send the correct total file size in the Content-Range header, so OneDrive no longer rejects chunks and Google Drive reliably finalizes the uploaded file.
  • Fix: Backblaze B2 uploads now stream large archives via the B2 large-file API instead of loading the whole file into memory, eliminating out-of-memory fatals on large backups.
  • Fix: Each remote destination now keeps its own resumable-upload checkpoint, preventing one provider from reusing another provider’s in-progress upload when the same archive is sent to multiple destinations.
  • Fix: A backup destination that exhausts its retries is now recorded and skipped on later resumptions, so an unreachable destination can no longer loop a backup indefinitely; the backup completes with warnings instead.
  • Fix: Resuming between destinations now advances the resumption counter correctly, preventing duplicate work and intermittent upload errors during multi-destination backups.

1.28.0

  • New: S3 and Cloudflare R2 destinations now include a cleanup tool to list and abort orphaned incomplete multipart uploads left behind by interrupted backups. AWS and R2 charge for stored parts until they are explicitly aborted; the new admin endpoints expose this via the storage settings page.
  • Fix: Google Drive, Dropbox, and OneDrive uploads now stream archive data in chunks instead of loading the entire file into memory, eliminating out-of-memory fatals when uploading large archives. Google Drive additionally recovers the server-side byte offset on WP-Cron resumption so interrupted uploads continue cleanly.
  • Fix: Out-of-memory fatals during the upload phase now show a specific message advising users to reduce the maximum archive size (Settings Archive) rather than the generic batch-size message, which does not apply to upload memory usage.
  • Fix: Eleven upload pipeline stability fixes: multipart upload abort on failure, per-provider retry budget enforcement, resumption slice guard to prevent starvation, progress stall detection, and more.

1.27.1

  • Fix: Resolved an infinite resumption loop during the upload phase when resumption_slice_seconds is configured and one or more remote providers fail before an S3/R2 destination. The per-provider retry delay could exhaust the execution slice budget, causing the S3 chunked upload to yield immediately on every segment without sending any data. The retry delay now yields the slice instead of blocking when the deadline is approaching. Additionally, already-completed provider uploads are now preserved across resumption segments so they are not re-run unnecessarily.

1.27.0

  • New: Upload failures are now logged per provider and recorded in job history. Jobs that succeed to at least one destination (but fail others) complete with a “Complete with Warnings” status and a yellow badge, keeping them restorable while surfacing the partial failure.
  • New: Storage providers that fail a connection test are marked “Unavailable” and disabled as backup destinations until re-tested — preventing silent backup omissions.
  • New: If the site’s encryption key has changed since credentials were last saved, affected providers are flagged with a “Key mismatch” badge and disabled until credentials are re-entered. An admin notice lists the affected providers and links to the storage settings page.
  • New: OAuth providers (Google Drive, OneDrive, Dropbox) now run an automatic connection test immediately after authorization redirect, so any permission or scope issue surfaces instantly.
  • New: Configurable per-provider upload retry: if an upload to a provider fails after all chunk-level retries are exhausted, BackupRidge retries the entire provider upload up to N times (default: 2) with a configurable delay (default: 30 s). If all retries fail, the provider is marked unavailable. Configure under Settings Upload.
  • Improved: AjaxHandler refactored into nine focused handler classes, reducing the largest file from ~5,200 to ~460 lines and making the codebase easier to audit.
  • Improved: Reviewer-parity error count reduced from 230 to 45 (structural floor — remaining items are genuine WordPress coding standards edge cases with inline justifications).

1.26.2

  • Fixed: Plugin Check gate now correctly handles the per-file output format introduced in Plugin Check 1.9.0, preventing findings from being silently missed.
  • Fixed: Applied esc_sql() to the migration preflight test table name in HandshakeValidator to satisfy Plugin Check 1.9.0’s new database parameter check.
  • Improved: Replaced string interpolation with concatenation in SearchReplace queries to remain compatible with Plugin Check’s annotation-stripping PHPCS mode.
  • Improved: Suppression baseline lowered from 16 to 14 (two now-unnecessary suppressions removed).

1.26.1

  • Fixed: Removed unnecessary ini_set('memory_limit') fallback — wp_raise_memory_limit() is always available on supported WordPress versions.
  • Fixed: Replaced strip_tags() with wp_strip_all_tags() per WordPress coding standards.
  • Improved: Added inline code comments explaining SQL identifier escaping, dynamic IN() list patterns, cron interval necessity, base64 encoding usage, and standalone download gateway patterns — making the codebase easier to audit and reducing false-positive flags during WordPress review.
  • Improved: Log file download now applies wp_strip_all_tags() before output.
  • Improved: Input sanitization applied at the point of read for array parameters in AJAX handlers.

1.26.0

Security release — please review the cron note below if you use system cron.

  • Important: The system-cron trigger now authenticates with an HTTP header (X-BackupRidge-Cron-Key) instead of a key in the URL, so the secret no longer leaks into server access logs or Referer headers. If you run BackupRidge from a system cron job, update it to the new command shown on the Settings page — the old ?key= URL will now return 403. To keep using the URL-key method, add define( 'BACKUPRIDGE_ALLOW_CRON_QUERY_KEY', true ); to wp-config.php.
  • Security: Backup archives and logs are now protected against direct web access with deny rules and an unguessable token in each filename.
  • Security: Blocked PHP object injection during restore search-and-replace.
  • Security: Test-only scaffolding AJAX handlers are no longer registered in production builds.
  • Security: The standalone download endpoint is now confined to the backup directory (path-traversal hardening).
  • Security: Backup downloads now send Referrer-Policy and X-Robots-Tag: noindex headers.
  • Security: Database identifiers are escaped through a single helper and ID lists use prepared statements.
  • Changed: On multisite, backup, restore, storage, and migration actions now require a network super-admin.
  • Changed: Documentation clarifies that archive encryption uses AES-256-GCM authenticated encryption (legacy AES-256-CBC archives remain decryptable for restore).

For the complete version history, see the plugin’s SVN changelog.