Directory / plugin
Ozeki Database Backup for S3
v0.4.1 · by Ozeki
Back up WordPress databases and uploads to Amazon S3 without storing long-lived AWS access keys in WordPress.
About this plugin
Ozeki Database Backup for S3 is a security-focused WordPress database and uploaded-media backup plugin for Amazon S3.
The plugin is designed for environments where WordPress can obtain AWS credentials through the AWS SDK for PHP default credential provider chain, such as an EC2 instance using an IAM role.
The plugin does not provide fields for storing an AWS Access Key ID or Secret Access Key in the WordPress database.
Current features include:
- Manual database backups from WordPress administration.
- Automatic daily database backups using WP-Cron.
- WP-CLI database backup command.
- WP-CLI backup status command.
- Gzip-compressed SQL database backups.
- Amazon S3 upload using the AWS SDK for PHP.
- Native
mysqldumpormariadb-dumpwhen available. - PHP-based database dump fallback when native database dump utilities or process execution are unavailable.
- Configurable retention using any positive integer keep count.
- Backup history stored locally in WordPress.
- S3 connection testing with temporary test objects.
- Automatic cleanup of plugin Cron events when the plugin is deactivated.
- On-demand uploads-directory backups started from WordPress administration.
- Background media inventory, checksum preparation, multipart upload, and verification using WordPress Cron.
- Per-file SHA-256 inventory and a final S3 completion marker.
- WP-CLI media status, worker, preparation, submission, and explicit failed-job cleanup commands.
AWS authentication
Ozeki Database Backup for S3 uses the AWS SDK for PHP default credential provider chain.
The plugin does not ask you to enter an AWS Access Key ID or Secret Access Key in the WordPress administration interface and does not intentionally store long-lived AWS credentials in the WordPress database.
For WordPress hosted on Amazon EC2, using an IAM role attached to the EC2 instance is recommended.
Other credential sources supported by the AWS SDK default credential provider chain may also work, depending on the hosting environment.
The AWS identity used by WordPress must have appropriate permissions for the configured S3 bucket and prefix.
Database backup
Database backups are created as SQL dumps, compressed with gzip, and uploaded to the configured S3 bucket.
Database backups verify that gzip expansion matches the original SQL, send a SHA-256 checksum, and check the stored S3 object’s size and checksum before reporting success. New history entries include the compressed file’s SHA-256 and an S3 integrity verification state. Older backups are not automatically marked verified. S3 integrity verification does not mean that a database restore has been tested.
This verification requires permission to read object metadata and checksums, in addition to upload permission. Check the applicable encryption permissions when using KMS. A verification failure prevents success-dependent retention; an object already uploaded before the failure may remain in S3 for inspection. Database backups remain single-object uploads, not multipart jobs.
Backup objects are stored below:
<configured-prefix>/backups/database/YYYY/MM/DD/
The plugin prefers a native MySQL-compatible dump utility such as mysqldump or mariadb-dump when available.
When a suitable native dump utility or PHP process execution is unavailable, the plugin can use its PHP database dump backend instead.
Media backup
Media backup covers regular files below the current single-site WordPress uploads directory. It is separate from database backup and must be started explicitly.
Media jobs prepare a sorted file inventory and SHA-256 checksums in bounded background steps, upload files as individual S3 objects, and publish a completion marker only after the inventory and uploaded objects have been verified. Large files use S3 multipart upload.
Media objects are stored below:
<configured-prefix>/backups/media/<random-job-id>/
Before media backup can be started from WordPress administration, the server administrator must define ODBFS3_MEDIA_WORK_DIR in wp-config.php. Its value must be an existing persistent POSIX directory owned by the WordPress PHP user, with mode 0700, outside the web root, wp-content, and uploads. Do not use a publicly served path or a temporary directory that may be cleared while a job is running.
For example:
define('ODBFS3_MEDIA_WORK_DIR', '/private/persistent/wordpress-media-work');
Keep the uploads tree unchanged while a media backup runs. New, removed, renamed, or changed files or directories can stop the job safely. Media backup has no automatic schedule or retention in this release. A failed job must be inspected and its exact Job ID explicitly cleaned with WP-CLI before another media job is submitted.
This release does not provide a production media restore command. The S3 completion marker and inventory are intended to support independent restoration and full SHA-256 verification. A complete WordPress recovery requires both an appropriate database backup and the corresponding media backup.
Automatic database backups and WP-Cron
Automatic backups use WordPress WP-Cron.
WP-Cron is triggered by WordPress requests and is not a real-time operating system scheduler. A backup scheduled for a particular time may therefore run later if the site receives no requests around that time.
For environments where predictable execution is important, use an operating system scheduler to run WordPress Cron periodically.
For a standard WP-CLI installation, an example is:
*/5 * * * * cd /path/to/wordpress && wp cron event run --due-now --quiet
For a Docker Compose installation with a WP-CLI service, an example is:
*/5 * * * * cd /path/to/docker-project && docker compose run --rm wp-cli cron event run --due-now --quiet
These are examples only. Paths, users, container configuration, and execution permissions depend on your hosting environment.
Retention
Retention can be disabled or configured with any positive integer as the number of latest database backups to keep.
Retention operates only on database backup objects matching the plugin’s expected backup naming structure below the configured S3 prefix.
Manual backups do not automatically apply retention.
Automatic backups and backups executed through the plugin’s WP-CLI backup command apply the configured retention policy after a successful backup.
Version 0.4.1 safeguard: before deleting older backups, retention checks the retained objects against their original SHA-256 metadata and S3 checksums. Missing evidence, mismatches, denied checks or incomplete listings stop cleanup. Older backups without this metadata can defer cleanup until enough newer verified backups exist. Backup success and retention failure remain separate results. These safeguards are introduced in 0.4.1.
Uninstall behavior
Deactivating the plugin removes its scheduled database and media WordPress Cron events but keeps plugin settings, backup history, and media job state.
Uninstalling the plugin removes its local WordPress settings, backup history, current media job state, and archived media job metadata.
Uninstalling Ozeki Database Backup for S3 does NOT delete database or media backups stored in Amazon S3. It also does not automatically remove private media work directories or discover unknown incomplete multipart uploads.
Recovery Set collector, observation, execution, schedule-assessment and cleanup records are retained on uninstall. Stop any externally registered Recovery Set schedule separately and preserve recovery evidence before planning manual retirement. Automated export and final deletion of these records are not provided in this release.
This is intentional. Remote backups should not disappear merely because the WordPress plugin is removed.
External Service
Ozeki Database Backup for S3 connects to Amazon Web Services (AWS), specifically Amazon Simple Storage Service (Amazon S3), in order to store and manage database and media backup objects.
The plugin uses the AWS SDK for PHP to communicate with AWS.
When the plugin performs a database backup, it sends the following to Amazon S3:
- The configured S3 bucket name.
- The configured S3 object prefix and generated backup object key.
- The gzip-compressed SQL database backup file.
When the plugin performs a media backup, it sends the following to Amazon S3:
- The configured S3 bucket name.
- The configured S3 object prefix and generated media backup keys.
- Files from the WordPress uploads directory.
- A generated inventory containing relative paths, sizes, SHA-256 checksums, and object mappings.
- A generated completion marker after all media objects and the inventory have been verified.
Media upload and verification may create, list, inspect, complete, or abort multipart uploads and may inspect uploaded objects. Explicit cleanup of an exact failed media job may abort only its recorded incomplete multipart upload. The plugin does not automatically delete completed media backup objects.
Files in the WordPress uploads directory may contain personal, private, copyrighted, or otherwise sensitive content. Administrators are responsible for selecting an appropriate S3 destination, access policy, encryption configuration, retention policy, and legal basis for storing that content.
A database backup may contain any information stored in the WordPress database. Depending on the site, this may include personal or sensitive data such as user accounts, email addresses, post content, comments, plugin settings, and other database records.
When the S3 connection test is run, the plugin:
- Checks access to the configured bucket.
- Creates a temporary test object containing a generated test string and timestamp.
- Reads the temporary object back to verify access.
- Deletes the temporary test object.
Retention operations may list and delete database backup objects within the configured backup prefix according to the selected retention policy.
Use of Amazon S3 is subject to Amazon Web Services terms and privacy policies:
AWS Customer Agreement:
https://aws.amazon.com/agreement/
AWS Privacy Notice:
https://aws.amazon.com/privacy/
AWS Service Terms:
https://aws.amazon.com/service-terms/
No telemetry, analytics, advertising, or unrelated tracking data is intentionally sent by Ozeki Database Backup for S3 to the plugin author.
WP-CLI
Create a database backup:
wp ozeki-database-backup-for-s3 backup
Display backup configuration and status:
wp ozeki-database-backup-for-s3 status
Queue media preparation and upload using an existing private work directory:
wp ozeki-database-backup-for-s3 media enqueue /private/persistent/wordpress-media-work
Display safe media job status:
wp ozeki-database-backup-for-s3 media status
Run one bounded media worker callback, for example from a server scheduler:
wp ozeki-database-backup-for-s3 media tick
For a directory that exceeds the background enumeration budget, prepare and submit from WP-CLI:
wp ozeki-database-backup-for-s3 media prepare /private/persistent/wordpress-media-work
wp ozeki-database-backup-for-s3 media start /private/persistent/wordpress-media-work/odbfs3-preparation-...
After inspecting an exact failed media job, explicitly clean only its recorded incomplete multipart upload and private workspace:
wp ozeki-database-backup-for-s3 media cleanup <job-id> --yes
Recovery Sets (introduced in 0.4.0)
Settings > Recovery Sets displays existing site-local sets, component/manifest verification, later observations, execution records and cleanup journal progress. Reading the page does not create sets, contact S3, run restore tests or delete files. Existing standalone backup history is not automatically converted into sets.
Administrators can explicitly save schedule-assessment settings on this page: enabled/stopped, first expected time (UTC), period and start/completion grace (seconds). These settings only assess expectations; they do not start, stop or reschedule actual Cron jobs. Saving requires confirmation, a valid nonce and the current settings revision. Stale forms are rejected; reload before retrying. Resuming assessment requires a future first expected time. Unfinished execution records are preserved and do not prove that a worker is alive. Read-only JSON is available through recovery-set execution and recovery-set schedule-status with –source-id and –format=json.
WP-CLI commands (replace IDs with 32 lowercase hexadecimal characters):
wp ozeki-database-backup-for-s3 recovery-set status <set-id> --format=json
wp ozeki-database-backup-for-s3 recovery-set latest --source-id=<source-id> --format=json
wp ozeki-database-backup-for-s3 recovery-set observations <set-id> --format=json
Exit code 0 means a successful read, not successful backup/restore. Inspect phase, completeness, index/aggregation completeness and observation freshness. Indexes are bounded to 100 records and report incomplete results explicitly. Observation freshness defaults to 24 hours; refreshing the page does not revalidate S3.
Recovery Set Cron is a developer integration through WordPressRecoverySchedule::register with fixed configuration, locking adapters and a result reporter. It is not enabled by activation or the existing daily database-backup setting. Each invocation advances one operation; repeated calls are needed to finish a set. Daily slots use UTC. Failed sets, missing evidence and configuration changes require review; do not delete journals to force a retry. Stop the external scheduler and unschedule the exact integration hook before maintenance; deactivation does not manage externally registered Recovery Set schedules.
Inspect local cleanup first:
wp ozeki-database-backup-for-s3 recovery-set cleanup-plan <set-id> --workspace-parent=<private-parent> --format=json
After confirming recovery materials and the plan, explicitly execute:
wp ozeki-database-backup-for-s3 recovery-set cleanup <set-id> --workspace-parent=<private-parent> --confirm-set=<same-set-id> --format=json
Only completed database.sql and database.sql.gz temporary files are eligible, with a 1 GiB limit per file. The command revalidates hashes under a lock and records deletion progress. Evidence, media subtrees and S3 objects are retained. If interrupted, review the reason and resume with the same ID and parent; preserve the journal. This is not automatic/recursive cleanup or a current S3 availability check.
There is no general Recovery Set create/restore command or acquisition configuration UI. The schedule-assessment form does not configure acquisition. DB/media correspondence does not guarantee a point-in-time snapshot. Local records are not independently signed. See the repository docs/recovery-operations.md for integration, stopping and incident procedures. These operations were introduced in 0.4.0.