Amazon S3 provider
The Media Library feature is powered by a back-end server package called Upload which leverages the use of providers.
Strapi maintains 3 providers for the Media Library. The present page is about the Cloudinary provider installation and configuration. For other providers, please refer to the list in the Media Library page.
Installation
To install the official Strapi-maintained AWS S3 provider, run the following command in a terminal:
- Yarn
- NPM
yarn add @strapi/provider-upload-aws-s3
npm install @strapi/provider-upload-aws-s3 --save
Configuration
Providers configuration are defined in the /config/plugins file. If this file does not exist, you must create it. The provider configuration accepts the following entries:
providerto define the provider name (i.e.,cloudinary)providerOptionsto define options that are passed down during the construction of the provider (see AWS documentation for the full list of options)actionOptionsto define options that are passed directly to the parameters to each method respectively. The Official AWS documentation lists available options for upload/uploadStream and delete.
The following is an example configuration:
- JavaScript
- TypeScript
module.exports = ({ env }) => ({
// ...
upload: {
config: {
provider: 'aws-s3',
providerOptions: {
baseUrl: env('CDN_URL'),
rootPath: env('CDN_ROOT_PATH'),
s3Options: {
credentials: {
accessKeyId: env('AWS_ACCESS_KEY_ID'),
secretAccessKey: env('AWS_ACCESS_SECRET'),
},
region: env('AWS_REGION'),
params: {
ACL: env('AWS_ACL', 'public-read'),
signedUrlExpires: env('AWS_SIGNED_URL_EXPIRES', 15 * 60),
Bucket: env('AWS_BUCKET'),
},
},
},
actionOptions: {
upload: {},
uploadStream: {},
delete: {},
},
},
},
// ...
});
// ...
upload: {
config: {
provider: 'aws-s3',
providerOptions: {
baseUrl: env('CDN_URL'),
rootPath: env('CDN_ROOT_PATH'),
s3Options: {
credentials: {
accessKeyId: env('AWS_ACCESS_KEY_ID'),
secretAccessKey: env('AWS_ACCESS_SECRET'),
},
region: env('AWS_REGION'),
params: {
ACL: env('AWS_ACL', 'public-read'),
signedUrlExpires: env('AWS_SIGNED_URL_EXPIRES', 15 * 60),
Bucket: env('AWS_BUCKET'),
},
},
},
actionOptions: {
upload: {},
uploadStream: {},
delete: {},
},
},
},
// ...
});
If you're using the bucket as a CDN and deliver the content on a custom domain, you can get use of the baseUrl and rootPath properties and use environment configurations to define how your assets URLs will be saved inside Strapi.
- Strapi has a default
securitymiddleware that has a very strictcontentSecurityPolicythat limits loading images and media to"'self'"only, see the example configuration on the provider page or the middleware documentation for more information. - When using a different provider per environment, specify the correct configuration in
/config/env/${yourEnvironment}/plugins.js|ts(see environments).
Bucket CORS configuration
If you are planning on uploading content like GIFs and videos to your S3 bucket, you will want to edit its CORS configuration so that thumbnails are properly shown in Strapi. To do so, open your Bucket on the AWS console and locate the Cross-origin resource sharing (CORS) field under the Permissions tab, then amend the policies by writing your own JSON configuration, or copying and pasting the following one:
[
{
"AllowedHeaders": ["*"],
"AllowedMethods": ["GET"],
"AllowedOrigins": ["YOUR STRAPI URL"],
"ExposeHeaders": [],
"MaxAgeSeconds": 3000
}
]
Required AWS policy actions
The following are the minimum amount of permissions needed for AWS S3 provider to work:
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:ListBucket",
"s3:DeleteObject",
"s3:PutObjectAcl"
],
Private AWS S3 provider
You can set up a private provider, meaning that every asset URL displayed in the Content Manager will be signed for secure access.
To create a private aws-s3 provider:
- Create a
/providers/aws-s3folder in your application (see local providers for more information). - Implement the
isPrivate()method in theaws-s3provider to returntrue. - Implement the
getSignedUrl(file)method in theaws-s3provider to generate a signed URL for the given file.
- JavaScript
- TypeScript
module.exports = {
init: (config) => {
const s3 = new AWS.S3(config);
return {
async upload(file) {
// code to upload file to S3
},
async delete(file) {
// code to delete file from S3
},
async isPrivate() {
return true;
},
async getSignedUrl(file) {
const params = {
Bucket: config.params.Bucket,
Key: file.path,
Expires: 60, // URL expiration time in seconds
};
const signedUrl = await s3.getSignedUrlPromise("getObject", params);
return { url: signedUrl };
},
};
},
};
export = {
init: (config) => {
const s3 = new AWS.S3(config);
return {
async upload(file) {
// code to upload file to S3
},
async delete(file) {
// code to delete file from S3
},
async isPrivate() {
return true;
},
async getSignedUrl(file) {
const params = {
Bucket: config.params.Bucket,
Key: file.path,
Expires: 60, // URL expiration time in seconds
};
const signedUrl = await s3.getSignedUrlPromise("getObject", params);
return { url: signedUrl };
},
};
},
};