Amazon S3 Integration
Amazon S3 (Simple Storage Service) is a scalable object storage service provided by AWS. Sveltia CMS supports S3 as a media storage backend with direct browser-to-S3 uploads using AWS Signature Version 4 — no backend proxy is required.
Requirements
- An AWS account with an S3 bucket created.
- An IAM user with an access key and the minimum required permissions (see Credentials below).
CSP
If your site uses a Content Security Policy (CSP), you need to allow the S3 endpoint. See Content Security Policy below for details.
Setup
Credentials
Create an IAM user with programmatic access and attach a policy granting the minimum required permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:ListBucket", "s3:GetObject", "s3:PutObject"],
"Resource": ["arn:aws:s3:::my-bucket", "arn:aws:s3:::my-bucket/*"]
}
]
}The resulting Access Key ID goes in access_key_id in your config. The Secret Access Key is entered by users in the CMS UI when they access the media library for the first time — it is never stored in config.
Public Read Access
Asset preview and download URLs are unsigned direct storage URLs, so objects must be publicly readable:
- In the S3 console, open the bucket's Permissions tab.
- Under Block Public Access, disable
BlockPublicPolicyandRestrictPublicBuckets. - Add a bucket policy granting
s3:GetObjectto"Principal": "*"for the objects path:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/cms-uploads/*"
}
]
}CORS
Configure cross-origin resource sharing in the S3 console under Bucket > Permissions > Cross-origin resource sharing (CORS). CORS is required because Sveltia CMS sends custom AWS Signature v4 headers that trigger a preflight request.
[
{
"AllowedHeaders": ["*"],
"AllowedMethods": ["GET", "PUT", "HEAD"],
"AllowedOrigins": ["https://your-cms-domain.com"],
"ExposeHeaders": ["ETag"],
"MaxAgeSeconds": 3000
}
]Bucket Naming
For virtual-hosted-style URLs (the default), the bucket name must be DNS-compatible: lowercase letters, numbers, and hyphens only. If your bucket name contains underscores, use force_path_style: true in your config.
Configuration
Here’s an example configuration for Amazon S3:
media_libraries:
aws_s3:
access_key_id: AKIAIOSFODNN7EXAMPLE
bucket: my-website-assets
region: us-east-1
prefix: cms-uploads/ # Optional
force_path_style: false # Optional, see Bucket Naming above
public_url: https://media.example.com # Optional, see Custom Domain below[media_libraries.aws_s3]
access_key_id = "AKIAIOSFODNN7EXAMPLE"
bucket = "my-website-assets"
region = "us-east-1"
prefix = "cms-uploads/"
force_path_style = false
public_url = "https://media.example.com"{
"media_libraries": {
"aws_s3": {
"access_key_id": "AKIAIOSFODNN7EXAMPLE",
"bucket": "my-website-assets",
"region": "us-east-1",
"prefix": "cms-uploads/",
"force_path_style": false,
"public_url": "https://media.example.com"
}
}
}{
media_libraries: {
aws_s3: {
access_key_id: 'AKIAIOSFODNN7EXAMPLE',
bucket: 'my-website-assets',
region: 'us-east-1',
prefix: 'cms-uploads/', // Optional
force_path_style: false, // Optional
public_url: 'https://media.example.com', // Optional
},
},
}WARNING
Do not write your Secret Access Key in the configuration file, as it should be kept confidential and not exposed in client-side code. Users will be prompted to enter the key when they use the storage first time, which will be stored securely in the browser’s local storage.
Configuration Properties
| Property | Required | Description |
|---|---|---|
access_key_id | Yes | AWS Access Key ID (safe to store in config). |
bucket | Yes | The S3 bucket name. |
region | Yes | AWS region, e.g. us-east-1, eu-west-1. |
prefix | No | Path prefix within the bucket, e.g. uploads/. |
force_path_style | No | Use path-style URLs (s3.region.amazonaws.com/bucket) instead of virtual-hosted-style (bucket.s3.region.amazonaws.com). Defaults to false. |
public_url | No | Custom domain for asset URLs (e.g. a CloudFront distribution). See Custom Domain below. |
Custom Domain
If you serve assets through a CloudFront distribution or a Route 53 custom domain pointing to your S3 bucket, set public_url to that URL. Asset preview and download URLs in the CMS will use the custom domain instead of the S3 endpoint:
public_url: 'https://media.example.com'The S3 API endpoint is still used for listing and uploading — only the asset URLs shown in the CMS change. See the Route 53 getting-started guide for setting up a custom domain with S3.
Content Security Policy
The URL pattern depends on whether force_path_style is enabled.
Virtual-hosted-style (default) — https://{bucket}.s3.{region}.amazonaws.com:
connect-src https://*.s3.us-east-1.amazonaws.com;
img-src https://*.s3.us-east-1.amazonaws.com;Path-style (force_path_style: true) — https://s3.{region}.amazonaws.com/{bucket}:
connect-src https://s3.us-east-1.amazonaws.com;
img-src https://s3.us-east-1.amazonaws.com;Replace us-east-1 with your actual bucket region.
If using a custom domain via public_url, add it to img-src as well:
connect-src https://*.s3.us-east-1.amazonaws.com;
img-src https://*.s3.us-east-1.amazonaws.com
https://media.example.com;See the CSP documentation for more details.
Accessing the Storage
The Amazon S3 media storage can be accessed through the File and Image fields in Sveltia CMS. Enter your Secret Access Key in the CMS UI when prompted, and you’ll be able to upload new media directly to S3 or select existing media from your bucket.
When uploading media, files will be stored in your S3 bucket, and you can take advantage of S3’s capabilities directly from the CMS. You can also select existing media from your S3 storage.
Future Plans
You’ll be able to manage your S3 files directly from the Asset Library in future releases.