Performance mode requires bucket CORS
You may see this message after Test connection on a CDN:
> Performance mode requires bucket CORS
This article explains what that means, which CDNs need a manual CORS rule, and exactly what to paste — so you can finish setup even if the script could not push CORS automatically.
---
Where this shows up
Admin → Servers → Servers management → Add new CDN (or edit an existing CDN)
Turn on Performance mode (*Direct upload and download (bypass main server)*), save credentials, then click Test connection.
---
What Performance mode does
| Performance mode | How files move |
|---|---|
| On (usual default) | The visitor’s browser talks directly to the CDN bucket (presigned upload/download). Faster for you — less load on the main VPS |
| Off | Uploads and downloads go through the main server (proxy). CORS on the bucket is not required for that path |
When Performance mode is on, the browser must be allowed to call the bucket from your site’s domain. That permission is called CORS (Cross-Origin Resource Sharing).
Without the right CORS rule, credentials can still be “valid,” but direct uploads fail. Members may see errors about Performance mode and CORS.
---
XFile Ultra usually pushes CORS for you
On Test connection and when creating a direct upload URL, the script tries to write the CORS rule automatically to the bucket (best effort).
That often works when your access key has permission to change CORS (for example a full-access Spaces key, or an R2 token with Admin Read & Write).
Use this article when auto-setup fails — wrong key permissions, provider UI only, or a temporary API error — so you can paste the rule yourself and continue.
---
Contabo — usually no CORS setup needed
Contabo Object Storage is special.
- Contabo typically allows browser CORS by default, even when the API shows an empty CORS config
- XFile Ultra does not treat Contabo like “CORS required” after a successful Test connection
- You normally do not need to paste a CORS policy for Contabo
If Contabo uploads still fail with Performance mode on, double-check endpoint, bucket name, and keys first. Turning Performance mode off is a temporary workaround (traffic proxies through your VPS).
---
The CORS rule every other CDN should use
Replace YOUR-DOMAIN.com with your real site domain (the same host visitors use for XFile Ultra). Include both apex and www if you use both.
[
{
"AllowedOrigins": [
"https://YOUR-DOMAIN.com",
"https://www.YOUR-DOMAIN.com"
],
"AllowedMethods": ["GET", "PUT", "HEAD"],
"AllowedHeaders": ["content-type", "content-length"],
"ExposeHeaders": ["ETag"],
"MaxAgeSeconds": 86400
}
]What this means in plain words:
| Field | Value | Why |
|---|---|---|
| AllowedOrigins | Your site HTTPS URLs | Only your site may talk to the bucket from the browser |
| AllowedMethods | GET, PUT, HEAD | Download, upload, and light checks |
| AllowedHeaders | content-type, content-length | Required for uploads (do not use * on Cloudflare R2) |
| ExposeHeaders | ETag | Lets the browser see upload confirmation headers |
| MaxAgeSeconds | 86400 | Browser may cache the CORS answer for 24 hours |
---
Amazon S3
1. Open Amazon S3 → your bucket
2. Permissions → Cross-origin resource sharing (CORS) → Edit
3. Paste this JSON (fix the domain), then Save
[
{
"AllowedOrigins": [
"https://YOUR-DOMAIN.com",
"https://www.YOUR-DOMAIN.com"
],
"AllowedMethods": ["GET", "PUT", "HEAD"],
"AllowedHeaders": ["content-type", "content-length"],
"ExposeHeaders": ["ETag"],
"MaxAgeSeconds": 86400
}
]Then in XFile Ultra: edit the CDN → Test connection again with Performance mode on.
---
Wasabi
Wasabi is S3-compatible. XFile Ultra usually pushes CORS automatically, and the admin form does not show a long CORS panel for Wasabi.
If direct uploads still fail:
1. Open the Wasabi console → your bucket → CORS / permissions settings (wording varies by console version)
2. Paste the same JSON rule as Amazon S3
3. Save, then Test connection in XFile Ultra
[
{
"AllowedOrigins": [
"https://YOUR-DOMAIN.com",
"https://www.YOUR-DOMAIN.com"
],
"AllowedMethods": ["GET", "PUT", "HEAD"],
"AllowedHeaders": ["content-type", "content-length"],
"ExposeHeaders": ["ETag"],
"MaxAgeSeconds": 86400
}
]---
Cloudflare R2
R2 is picky: do not use AllowedHeaders: ["*"]. Use the explicit headers below.
1. Cloudflare dashboard → R2 Object Storage → open your bucket
2. Settings → CORS policy → Add
3. Paste this JSON and save
[
{
"AllowedOrigins": [
"https://YOUR-DOMAIN.com",
"https://www.YOUR-DOMAIN.com"
],
"AllowedMethods": ["GET", "PUT", "HEAD"],
"AllowedHeaders": ["content-type", "content-length"],
"ExposeHeaders": ["ETag"],
"MaxAgeSeconds": 86400
}
]Tip: Auto CORS push needs an API token that can write CORS (often Admin Read & Write). Object Read & Write alone may be enough for files but not for updating the CORS policy.
---
DigitalOcean Spaces
DigitalOcean often applies CORS automatically with a full-access Spaces key. If Test connection still says CORS is required:
1. DigitalOcean → Spaces Object Storage → open your Space
2. Settings → CORS Configurations → Edit
3. Add a rule with:
| Field | Value |
|---|---|
| Origins | https://YOUR-DOMAIN.com and https://www.YOUR-DOMAIN.com (separate origin entries) |
| Allowed methods | GET, PUT, HEAD |
| Allowed headers | content-length, then content-type |
| Access control max age | 86400 |
Or paste the same JSON if your Spaces editor accepts JSON:
[
{
"AllowedOrigins": [
"https://YOUR-DOMAIN.com",
"https://www.YOUR-DOMAIN.com"
],
"AllowedMethods": ["GET", "PUT", "HEAD"],
"AllowedHeaders": ["content-type", "content-length"],
"ExposeHeaders": ["ETag"],
"MaxAgeSeconds": 86400
}
]---
IDrive e2
IDrive often configures CORS automatically when the access key has read and write on all buckets. The Test connection probe may not always warn about CORS for IDrive, but if Performance mode uploads fail in the browser, set CORS manually:
1. IDrive e2 → Settings → Bucket CORS → CORS Configuration
2. Paste this JSON and save
[
{
"AllowedOrigins": [
"https://YOUR-DOMAIN.com",
"https://www.YOUR-DOMAIN.com"
],
"AllowedMethods": ["GET", "PUT", "HEAD"],
"AllowedHeaders": ["content-type", "content-length"],
"ExposeHeaders": ["ETag"],
"MaxAgeSeconds": 86400
}
]Also confirm the Service URL / endpoint uses https:// (HTTP is not supported).
---
Other S3-compatible storage
For any “Other” S3-compatible provider:
1. Find Bucket CORS / CORS configuration in that provider’s console
2. Paste the same JSON rule
3. Save, then Test connection in XFile Ultra
[
{
"AllowedOrigins": [
"https://YOUR-DOMAIN.com",
"https://www.YOUR-DOMAIN.com"
],
"AllowedMethods": ["GET", "PUT", "HEAD"],
"AllowedHeaders": ["content-type", "content-length"],
"ExposeHeaders": ["ETag"],
"MaxAgeSeconds": 86400
}
]If the provider’s editor wants XML instead of JSON, create one rule with the same origins, methods, headers, expose header, and max age as in the table above.
---
Checklist after you paste CORS
1. Origins match the real public site URL (https, correct domain, www if needed)
2. Methods include GET and PUT (HEAD recommended)
3. Headers include content-type and content-length (not * on R2)
4. CDN Performance mode is on
5. Click Test connection again
6. Try a small browser upload as a normal member
If you need a quick temporary fix while debugging CORS, turn Performance mode off so traffic proxies through the main server — then turn it back on once CORS is correct.
---
Common problems
Credentials OK, but “requires bucket CORS”
The key can see the bucket, but the browser is not allowed yet. Paste the rule above (or fix key permissions so auto-push can run).
Works on apex, fails on www (or reverse)
Add both origins to AllowedOrigins.
R2 rejects the policy
Remove wildcard headers. Use only content-type and content-length.
Contabo shows no CORS warning — is that broken?
No. Contabo is expected to work without a manual CORS paste in most cases.
Upload init error about Performance mode and CORS
Direct upload URL could not be created. Re-check keys, bucket name, endpoint, and CORS — then Test connection.
---