
Automating backups to AIOZ Storage with GitHub Actions turns a one-time migration into a recurring job, running on a schedule instead of something someone has to remember to do manually. This is a different task from a one-time migration guide, it's the same rclone remote configuration this series has already covered, wired into a GitHub Actions workflow that runs on a cron schedule instead of a single manual command. This article covers the exact workflow YAML, how to store AIOZ Storage credentials safely as GitHub secrets, and what to verify before trusting it as your actual backup mechanism.
TL;DR:
rclone sync on a cron schedule, no new tooling beyond what a manual rclone backup already uses.A cron schedule is the whole point here, backups that depend on someone remembering to run a command eventually stop happening reliably. GitHub Actions already runs on a cron trigger natively, and since AIOZ Storage's rclone remote configuration is already established elsewhere in this series, wiring it into a scheduled workflow doesn't require new tooling, just a place to run the same rclone command on a timer instead of by hand.
The access key and secret key from your AIOZ Storage access grant never belong in your repository, in the workflow file, or anywhere version-controlled. GitHub's repository secrets exist for exactly this: encrypted values, set once in your repo's settings, referenced in a workflow without ever appearing in the workflow file itself or in any log output. Add two secrets to your repository, AIOZ_ACCESS_KEY and AIOZ_SECRET_KEY, holding the values from the access grant you generated for this backup job specifically, scoped narrowly to just the bucket this workflow needs, not a broader credential reused from something else.
name: Backup to AIOZ Storage
on:
schedule:
- cron: '0 3 * * *' # daily at 03:00 UTC
workflow_dispatch: {} # allow manual runs too
jobs:
backup:
runs-on: ubuntu-latest
steps:
- name: Install rclone
run: curl https://rclone.org/install.sh | sudo bash
- name: Configure rclone remote
run: |
mkdir -p ~/.config/rclone
cat > ~/.config/rclone/rclone.conf << EOF
[aioz-storage]
type = s3
provider = Other
access_key_id = ${{ secrets.AIOZ_ACCESS_KEY }}
secret_access_key = ${{ secrets.AIOZ_SECRET_KEY }}
endpoint = https://s3.aiozstorage.network
EOF
- name: Run backup
run: rclone sync /path/to/backup-source aioz-storage:my-backup-bucket --log-file=rclone.log -v
- name: Upload log as artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: rclone-backup-log
path: rclone.logThis remote needs no extra setting for AIOZ Storage's upload rules. With provider = Other, rclone uses path-style URLs by default (force_path_style), which AIOZ Storage needs because bucket subdomains don't resolve. From v1.72.0, rclone also leaves the AWS SDK's default upload checksums off unless you set use_data_integrity_protections = true (rclone S3 docs). If an upload still fails with MissingContentLength, check rclone version and keep that option unset (not tested against AIOZ Storage; endpoint behavior checked Oct 19, 2026).
The cron: '0 3 *' line schedules a daily run at 3 AM UTC, standard cron syntax GitHub Actions supports directly. workflow_dispatch: {} adds the ability to trigger the same job manually from the GitHub UI, useful for testing the workflow without waiting for the schedule. The rclone config gets written fresh on every run rather than committed anywhere, built entirely from the two secrets and AIOZ Storage's known endpoint, the same remote structure covered in the migration guides, just generated at runtime instead of stored in a config file on a laptop.
rclone sync makes the destination match the source exactly, including deleting anything on the destination that no longer exists on the source, which is the correct behavior for a one-directional backup job: the backup should reflect the current state of what you're protecting, not accumulate files that were deleted from the source months ago. That's meaningfully different from rclone copy, which never deletes anything on the destination, and from rclone bisync, which synchronizes changes in both directions, a genuinely different tool for a genuinely different job, covered in a companion article specifically because bisync's two-way behavior needs more care than a one-way backup does.
Before this workflow ever runs on a real schedule against real data, rclone's own documentation on sync is direct about the risk: it recommends testing first "with the --dry-run or the --interactive/i flag" before trusting it, since sync is a destructive operation, it deletes anything on the destination that doesn't exist on the source. Run the workflow once manually with --dry-run added to the sync command, confirm the file list it reports matches what you'd actually expect to be added or removed, and only then remove the flag for the real scheduled runs.
A green checkmark on the workflow run means the rclone sync command exited successfully, it doesn't on its own confirm the backup actually contains what you expect. The -v flag and the uploaded log artifact in the workflow above exist specifically so you can check what actually happened on a given run, how many files transferred, whether anything errored partway through. Worth periodically checking that log, and periodically restoring from the backup bucket to confirm the files that come back are actually usable, the same "verified recoverability" discipline that matters for any backup strategy, a scheduled job running successfully for months is not proof the data it produced would actually restore correctly if you needed it.
How do you schedule a recurring backup to AIOZ Storage?
With a GitHub Actions workflow using a schedule trigger with cron syntax, running rclone sync against an AIOZ Storage remote on each scheduled run. No AIOZ-specific tooling is required beyond the rclone remote configuration already used for manual migrations.
Where should AIOZ Storage credentials go in a GitHub Actions workflow?
In GitHub's encrypted repository secrets, referenced in the workflow as ${{ secrets.NAME }}, never committed to the repository or written directly into the workflow file.
Why use rclone sync instead of rclone copy for a backup job?rclone sync makes the destination match the source exactly, including removing files deleted from the source, which is the correct behavior for a backup meant to reflect current state. rclone copy never deletes anything on the destination, which can let a backup accumulate stale files indefinitely.
Does a successful workflow run guarantee the backup is usable?
No. A green checkmark confirms the rclone sync command exited without error, not that the resulting backup would actually restore correctly. Periodically checking the transfer log and test-restoring from the backup bucket is the only way to confirm that directly.
Can this workflow be triggered manually, not just on a schedule?
Yes, with workflow_dispatch: {} added to the workflow's triggers, which adds a manual "Run workflow" button in GitHub's UI alongside the scheduled cron trigger.
What's the difference between this and the rclone migration guides in this series?
The migration guides cover a one-time move from another S3-compatible provider to AIOZ Storage. This workflow automates a recurring backup job, the same rclone remote configuration, run repeatedly on a schedule rather than once by hand.

Distributed storage keeps data on many independent nodes that act as one system. See how it works, replication vs erasure coding, its types and trade-offs.

Egress fees are charges for data leaving a storage provider's network. See what triggers them, how to estimate them, and what AIOZ Storage's docs say.

An object storage vector database keeps vectors in the storage layer, not a cluster. See how it differs, when to pick it, and where AIOZ Storage fits in.

AIOZ Storage vector database pricing line by line: upload, storage, queries, data searched and data returned, with a worked monthly example you can reuse.

Create a bucket and upload a file on AIOZ Storage in five steps: sign up, set a passphrase, add credits, and upload. Plus what the passphrase cannot recover.

The AIOZ Storage rate limit is 100 requests per second. See what the docs do and don't say, and how to stay under it with boto3 retries and a limiter.