How to use Cloudflare R2 for server backups
Cloudflare R2 is S3-compatible object storage with no egress fees, so pulling a backup back down costs nothing in bandwidth. Create a private bucket, create an API token with Object Read & Write scoped to that bucket, and point the AWS CLI at https://<ACCOUNT_ID>.r2.cloudflarestorage.com with the region set to auto. R2 has no versioning, so use a lifecycle rule for retention and a bucket lock rule if the server's token must not be able to delete backups.
Create the bucket
- In the Cloudflare dashboard, go to the R2 object storage page and select Create bucket.
- Enter a name: 3 to 63 characters, lowercase letters, numbers and hyphens, not starting or ending with a hyphen.
- Under Location, leave None for automatic placement, pick a location hint, or select Specify jurisdiction (see the table below).
- Select Create bucket.
Buckets are private by default. Leave public access and the r2.dev URL off for a backup bucket. With Wrangler, Cloudflare's CLI:
npx wrangler r2 bucket create acme-server-backups --location weur--locationis an optional location hint. Leave it out for automatic placement.--jurisdiction eucreates the bucket in a jurisdiction instead.
Location hints vs jurisdictions
| Location hint | Jurisdiction | |
|---|---|---|
| What it does | Best-effort placement near where you expect access | Objects are stored within that jurisdiction |
| Values | wnam, enam, weur, eeur, apac, oc | eu, fedramp (Enterprise, via Cloudflare), us |
| S3 endpoint | https://<ACCOUNT_ID>.r2.cloudflarestorage.com | https://<ACCOUNT_ID>.<JURISDICTION>.r2.cloudflarestorage.com |
| Changing it | Only honored the first time a bucket name is created | Can't be changed after creation |
Automatic placement picks the region closest to whoever sends the create request, which is your laptop if you run Wrangler there. Set a hint if your servers are elsewhere. Use a jurisdiction only when data residency is a requirement; such buckets only answer on their own endpoint.
Create a bucket-scoped API token
R2 has to be purchased on the account before you can create API tokens. Then:
- On the R2 object storage page, under Account Details, select Manage next to API Tokens.
- Choose Create Account API token. It belongs to the account, so it keeps working if the person who made it leaves. A User API token stops working when that user is removed.
- Under Permissions, choose Object Read & Write.
- Scope the token to the backup bucket only.
- Create the token and copy the Access Key ID and Secret Access Key. The secret is shown once.
| Permission | What it allows |
|---|---|
| Admin Read & Write | Create, list and delete buckets, edit bucket configuration, read, write and list objects |
| Admin Read only | List buckets, view configuration, read and list objects |
| Object Read & Write | Read, write and list objects in specific buckets |
| Object Read only | Read and list objects in specific buckets |
Object Read & Write can't touch bucket settings, so a server holding it can't change lifecycle or lock rules. It can overwrite and delete objects in its bucket, and R2 has no write-only option. Bucket locks, below, close that gap. You also need your account ID, shown in the dashboard, for the endpoint.
Configure the AWS CLI
aws configure --profile r2Enter the Access Key ID and Secret Access Key, and auto for the region. The SDK requires a region; R2 ignores it, and also treats an empty value or us-east-1 as auto. To skip --endpoint-url on every command, add the endpoint to the profile:
[profile r2]
region = auto
endpoint_url = https://<ACCOUNT_ID>.r2.cloudflarestorage.comThe examples below still pass --endpoint-url, which overrides the profile. Test by listing the bucket itself. A bucket-scoped token isn't meant for listing every bucket in the account, and rclone needs no_check_bucket = true with such a token; see rclone backups.
aws s3 ls s3://acme-server-backups/ --profile r2 --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.comUpload backups
aws s3 cp /var/backups/web-01-2026-10-03.tar.gz s3://acme-server-backups/web-01/2026-10-03.tar.gz --profile r2 --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com --only-show-errorsaws s3 sync /var/backups/web-01/ s3://acme-server-backups/web-01/ --profile r2 --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com --only-show-errors- Use unique, dated keys. Without versioning, an overwrite or delete on R2 is final.
- Don't add
--deletetosync. A wiped local directory would delete the backups. - Don't pass
--sse. R2 doesn't implement thex-amz-server-side-encryptionheader; it encrypts every object and its metadata at rest with AES-256 automatically. --storage-class STANDARD_IAstores an object in Infrequent Access.STANDARDis the default.
Expire old backups with lifecycle rules
In the dashboard, open the bucket, select Settings, then under Object Lifecycle Rules select Add rule, fill in the prefix and actions, and select Save changes. With Wrangler, logged in with npx wrangler login:
npx wrangler r2 bucket lifecycle add acme-server-backups expire-30d web-01/ --expire-days 30expire-30dis the rule's name andweb-01/its prefix. Leave the prefix empty to cover the whole bucket.--expire-days 30deletes objects 30 days after upload.--ia-transition-daysmoves objects to Infrequent Access after that many days. Objects can't be moved back to Standard by a lifecycle rule.--abort-multipart-dayscancels unfinished multipart uploads. Every bucket already has a default rule that does this after seven days.
Objects are typically removed within 24 hours of their expiration time; existing objects can take longer after a rule changes. If an expire and a transition fall within the same 24 hours, the expire wins. A bucket can have up to 1,000 rules. Managing them needs an admin-level token, which the server never holds.
Protect backups with bucket locks
R2 doesn't implement versioning or the S3 Object Lock API. Instead, bucket lock rules stop objects under a prefix from being deleted or overwritten for a number of days, until a date, or indefinitely. They cover existing objects as well as new ones, the strictest matching rule wins, and they override lifecycle rules.
npx wrangler r2 bucket lock add acme-server-backups lock-14d web-01/ --retention-days 14In the dashboard, the same rule is under the bucket's Settings tab, in the Bucket lock rules card. Keep the lock shorter than your lifecycle expiry: a lifecycle rule that tries to delete a locked object waits until the lock ends.
Anyone who can edit the bucket's configuration can remove a lock rule, with wrangler r2 bucket lock remove or in the dashboard. A lock stops a leaked object token, not a compromised Cloudflare admin login. Also, a bucket with lock rules can't be emptied until they are removed.
Verify a backup
aws s3 ls s3://acme-server-backups/web-01/ --recursive --human-readable --summarize --profile r2 --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.comaws s3 cp s3://acme-server-backups/web-01/2026-10-03.tar.gz /tmp/restore-test.tar.gz --profile r2 --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com && sha256sum /tmp/restore-test.tar.gz && tar -tzf /tmp/restore-test.tar.gz > /dev/null && echo OKCompare the hash with the one you recorded before upload. Because egress is free, a full test download of a Standard object costs one Class B operation per request; Infrequent Access adds a retrieval fee. See testing a restore.
What it costs
As of October 2026, Cloudflare lists:
| Standard | Infrequent Access | |
|---|---|---|
| Storage | $0.015 / GB-month | $0.01 / GB-month |
| Class A operations (writes, lists) | $4.50 / million | $9.00 / million |
| Class B operations (reads, heads) | $0.36 / million | $0.90 / million |
| Data retrieval | None | $0.01 / GB |
| Egress to the internet | Free | Free |
| Minimum storage duration | None | 30 days |
- Free every month, Standard only: 10 GB-month of storage, 1 million Class A and 10 million Class B operations.
DeleteObject,DeleteBucketandAbortMultipartUploadare free. So are requests rejected as unauthorized.- Usage is rounded up to the next billing unit: 1.1 GB-month is billed as 2.
ListObjects,PutObjectand each multipartUploadPartare Class A operations, soaws s3 synclistings count.
Example: 100 GB of Standard backups is billed as 90 GB-month after the free tier, or $1.35 a month, and a daily upload stays well inside the free operations. Infrequent Access only pays off for copies kept 30 days or more and rarely read, because it has retrieval fees and no free tier.
Limits and S3 differences that matter for backups
- No versioning: deletes and overwrites are permanent.
- No S3 Object Lock headers; use bucket lock rules.
- No bucket policies or ACLs: the API token is the only access control.
- No object tagging, so no tag-based rules.
- Objects up to 4.995 TiB; a single upload or part up to 4.995 GiB; at most 10,000 parts.
- One write per second to the same key; faster writes get HTTP 429.
- Jurisdiction buckets only answer on their jurisdiction endpoint, so most tools need one profile per jurisdiction.
- The region is always
auto.
A key that can upload can usually delete too. For backups an attacker cannot remove, see protecting backups from ransomware; to keep what is stored readable only by you, encrypt it before upload.
Frequently asked questions
- Is Cloudflare R2 egress really free?
- Yes. Cloudflare charges no egress for any storage class through the S3 API, Workers API or
r2.dev. Infrequent Access objects still have a $0.01 per GB retrieval fee as of October 2026. - What region do I use for R2 in the AWS CLI?
auto. The CLI needs a value but R2 doesn't use it. An empty value orus-east-1also maps toauto.- Does R2 support versioning or Object Lock?
- No versioning and no S3 Object Lock API. Use bucket lock rules to stop objects under a prefix from being deleted or overwritten for a period.
- Can an R2 API token be limited to one bucket?
- Yes. Tokens with Object Read & Write or Object Read only permission can be scoped to specific buckets.
- How much R2 storage is free?
- As of October 2026, 10 GB-month of Standard storage, 1 million Class A and 10 million Class B operations each month. The free tier doesn't cover Infrequent Access.
How this was checked
Commands, limits and prices were checked against these official pages, on October 3, 2026:
- Cloudflare R2 docs: Create new buckets
- Cloudflare R2 docs: Data location (location hints and jurisdictions)
- Cloudflare R2 docs: Authentication (API tokens)
- Cloudflare R2 docs: aws CLI
- Cloudflare R2 docs: rclone
- Cloudflare R2 docs: Object lifecycles
- Cloudflare R2 docs: Bucket locks
- Cloudflare R2 docs: Storage classes
- Cloudflare R2 docs: Pricing
- Cloudflare R2 docs: S3 API compatibility
- Cloudflare R2 docs: Limits
- Cloudflare R2 docs: Data security
- Cloudflare Wrangler commands: R2 (bucket create, lifecycle add, lock add)
- AWS CLI User Guide: Using endpoints in the AWS CLI
- AWS CLI reference: s3 cp