R2 doesn’t charge for egress, so it suits servers where partners download a lot. You can also pin a bucket to the EU jurisdiction.
Before you start
- A Cloudflare account with R2 enabled.
- Your Account ID: a 32-character hex string, shown on the R2 Overview page under Account Details. It’s also the first part of the bucket’s S3 API address.
1. Create the bucket
- In the Cloudflare dashboard, go to R2 object storage → Overview and select Create bucket.
- Pick the Location:
- Automatic or a location hint (for example Eastern Europe (EEUR)) only suggests where the data should live. It is not a guarantee, and the bucket uses the default endpoint.
- A jurisdiction (for example European Union) guarantees the data stays there, and the bucket gets its own endpoint (see step 3). Choose this if your contracts require data to stay in the EU. It can’t be changed after the bucket is created.
- Create the bucket.
Keep the bucket private
In the bucket’s Settings, leave Public Development URL disabled and don’t connect a Custom Domain. Either one makes every file readable by anyone who guesses its path. CloudFile doesn’t need them: download links in webhooks are signed and expire after an hour.
You can leave the other settings as they are. The default lifecycle rule that aborts unfinished multipart uploads after 7 days is fine. To upload files over 100 MB from the web file manager or through file requests, add a CORS policy that allows PUT from https://cloudfile.dev under Settings → CORS Policy (see Uploads from the browser). SFTP and FTP don’t need it.
2. Create an API token
R2 access keys come from an R2 API token scoped to your bucket.
-
On the R2 Overview page, under Account Details, select Manage next to API Tokens.
-
Choose Create Account API token. (A user token works too, but stops working if your user leaves the account.)
-
Under Permissions, choose Object Read & Write.
-
Under Specify bucket(s), choose Apply to specific buckets only and pick your bucket.
-
Create the token. Cloudflare shows a summary with three values, once:
- Token value (starts with
cfat_): not needed by CloudFile. - Access Key ID (32 characters): goes into CloudFile.
- Secret Access Key (64 characters): goes into CloudFile.
The summary also lists the endpoint to use under Use jurisdiction-specific endpoints for S3 clients.
- Token value (starts with
Copy the Access Key ID and Secret Access Key somewhere safe. Cloudflare won’t show the secret again. If they leak, open the token and select Roll to get new keys, then update them in CloudFile.
3. Connect it
In CloudFile, go to Storage → Add bucket and choose Cloudflare R2:
| Field | Value |
|---|---|
| Bucket | Your bucket name, e.g. my-files |
| Account ID | From Account Details, e.g. 9276e14e21f297b9b1b0779e028b6814 |
| Endpoint | Filled in from the Account ID: https://<account-id>.r2.cloudflarestorage.com |
| Access key ID | The Access Key ID from step 2 |
| Secret access key | The Secret Access Key from step 2 |
| Name | Optional, e.g. Production |
| Path-style URLs | On |
The endpoint never includes the bucket name. The bucket’s settings page shows its S3 API address as
https://<account-id>.r2.cloudflarestorage.com/my-files. If you paste that, CloudFile drops the /my-files part for you.
For a bucket in a jurisdiction, add the jurisdiction to the endpoint, for example https://<account-id>.eu.r2.cloudflarestorage.com for the EU. A location hint such as EEUR doesn’t change the endpoint. The region is always auto, so CloudFile sets it for you.
Click Test connection. CloudFile writes, reads and deletes a small test file. Then click Save.
4. Use it on a server
Open a server and pick the bucket under Settings → Storage. New files go to the bucket from then on. Files already on the server aren’t moved.
In the bucket, each SFTP user gets a folder, <prefix>/<username>/, and shared folders live in <prefix>/_shared/<name>/. Leave the prefix empty to put them at the bucket root.
Troubleshooting
- Writing a test file failed: The specified bucket does not exist. Either the bucket name is wrong, or the bucket is in a jurisdiction (for example the EU) and the endpoint is missing it. Use
https://<account-id>.eu.r2.cloudflarestorage.com. - Writing a test file failed with a DNS or connection error. The Account ID is wrong. Copy it again from Account Details. It’s a 32-character hex string.
- Writing a test file failed: Access Denied. The token is scoped to a different bucket, or it has only Object Read permission. Create a new token with Object Read & Write for this bucket.
- Writing a test file failed with an invalid access key or signature error. You pasted the
cfat_…token value instead of the Access Key ID and Secret Access Key shown with it, or the token was rolled since.
See Your own bucket for how files are laid out in the bucket.
Couchdrop alternative
SFTP To Go alternative