How to configure a CORS policy on a bucket
Web browsers stop JavaScript on one site from using files on another site, unless the other site allows it. The way a site allows it is called Cross-Origin Resource Sharing (CORS). A bucket allows nothing by default. A web page at https://www.example.com that loads files from your bucket with JavaScript therefore fails with a CORS error in the browser.
To allow it, you add a CORS policy to the bucket. The policy lists the sites, called origins, that can send requests to the bucket, and the kinds of requests they can send. Images and videos that a page shows with ordinary HTML tags don't need a CORS policy. You only need one when the page's JavaScript downloads or uploads files.
This guide walks you through adding a CORS policy with the AWS CLI, checking it and removing it.
Before you start
You need:
- A Managed Object Storage service with a bucket. To create them, see How to get started with UpCloud Managed Object Storage. The examples in this guide use the bucket
site-assets. - The AWS CLI with the
upcloudprofile, as in How to get started with UpCloud Managed Object Storage.
A CORS policy doesn't give anyone access to your files. The browser's requests still need permission of their own. Either the files are in a public read bucket, as in How to set up a public read bucket, or the page uses links that carry their own permission, as in How to perform basic Object Storage operations using AWS CLI.
Write the CORS policy
A CORS policy is a JSON document with one or more rules. This one lets JavaScript on https://www.example.com download files from the bucket:
{
"CORSRules": [
{
"AllowedOrigins": ["https://www.example.com"],
"AllowedMethods": ["GET", "HEAD"],
"AllowedHeaders": ["*"],
"ExposeHeaders": ["ETag"],
"MaxAgeSeconds": 3000
}
]
}Each field sets one part of the rule:
AllowedOriginslists the sites that can send requests. An origin is the scheme and host name, such ashttps://www.example.com, with no path or trailing slash. To allow several sites, list them all, for example["https://www.example.com", "https://admin.example.com"].AllowedMethodslists the kinds of requests that the sites can send.GETandHEADare for downloading. To let the page upload files too, addPUT.AllowedHeaderslists the request headers that the page can send.*allows any header.ExposeHeaderslists the response headers that the page's JavaScript can read, here the file'sETag.MaxAgeSecondssets how long the browser can remember the bucket's answer before it asks again.
Save the policy as cors.json, with your own site in AllowedOrigins.
Use the exact origins of your own sites. "AllowedOrigins": ["*"] allows every site on the internet, so use it only for files that any site may use.
Add the policy to the bucket
aws s3api put-bucket-cors --bucket <bucket-name> --cors-configuration file://cors.json --profile upcloudThe command prints nothing when it succeeds. A bucket has one CORS policy, so this replaces any policy that the bucket already has.
To see the bucket's policy, run:
aws s3api get-bucket-cors --bucket <bucket-name> --profile upcloud{
"CORSRules": [
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"GET",
"HEAD"
],
"AllowedOrigins": [
"https://www.example.com"
],
"ExposeHeaders": [
"ETag"
],
"MaxAgeSeconds": 3000
}
]
}Check the policy
Before a browser sends a request to another site, it asks that site whether the request is allowed. This first request is called a preflight request. To check the policy without a browser, send the same preflight request with curl. Use the URL of any file in the bucket and one of the origins in the policy:
curl -i -X OPTIONS https://<endpoint>/<bucket-name>/<file-path> -H "Origin: https://www.example.com" -H "Access-Control-Request-Method: GET"<endpoint> is the host name of the service's S3 endpoint, for example abcd1.upcloudobjects.com. You can find it on the service's Overview tab, under Public access.
HTTP/2 200
date: Wed, 28 Oct 2026 06:57:29 GMT
server: ViPR/1.0
...
access-control-allow-origin: https://www.example.com
access-control-expose-headers: ETag
access-control-allow-methods: GET, HEAD
access-control-max-age: 3000
content-length: 0The access-control-allow-origin header names your site, so a browser on that site goes ahead with the request. For a site that isn't in AllowedOrigins, or a method that isn't in AllowedMethods, the answer is HTTP/2 403 with an InvalidCorsRequest error and no access-control headers, so the browser blocks the request.
Remove the policy
aws s3api delete-bucket-cors --bucket <bucket-name> --profile upcloudThe command prints nothing when it succeeds. Browsers then block JavaScript requests from other sites again.
Next steps
- How to set up a public read bucket explains how to let anyone download the bucket's files.
- How to perform basic Object Storage operations using AWS CLI shows more commands for working with buckets and files, including links that expire.