I just thought I’d add a working example with the config I have made to my code to get it to work seeing as I had a lot of trouble getting things to display correctly on both Strapi and my front-end.
I use cloudformation to deploy my service on the cloud so I have attached a couple of code extract in the hope it helps someone.
I have added the following variables in my .env file. Note for local development I still use the local upload provider.
CORS_ALLOWED_ORIGINS=["*"]
#AWS + s3 upload provider variables
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_REGION=
UPLOAD_AWS_BUCKET_NAME=
UPLOAD_IMAGE_PROVIDER=local
UPLOAD_MEDIA_SOURCE=["'self'", "data:", "blob:", "dl.airtable.com"]
This is my middlewares.ts config file:
export default ({ env }) => [
"strapi::errors",
{
name: "strapi::security",
config: {
contentSecurityPolicy: {
useDefaults: true,
directives: {
"connect-src": ["'self'", "https:"],
"img-src": env.array("UPLOAD_MEDIA_SOURCE", ["*"]),
"media-src": env.array("UPLOAD_MEDIA_SOURCE", ["*"]),
upgradeInsecureRequests: null,
},
},
},
},
{
name: "strapi::cors",
config: {
origin: env.array("CORS_ALLOWED_ORIGINS", ["*"]),
},
},
"strapi::poweredBy",
"strapi::logger",
"strapi::query",
"strapi::body",
"strapi::session",
"strapi::favicon",
"strapi::public",
];
Finally, this is my plugins.ts files
export default ({ env }) => ({
"users-permissions": {
config: {
jwt: {
expiresIn: "7d",
},
},
},
upload: {
config: {
provider: env("UPLOAD_IMAGE_PROVIDER", "local"),
providerOptions: {
accessKeyId: env("AWS_ACCESS_KEY_ID"),
secretAccessKey: env("AWS_SECRET_ACCESS_KEY"),
region: env("AWS_REGION"),
params: {
Bucket: env("UPLOAD_AWS_BUCKET_NAME"),
},
},
},
},
});
These are the values I pass into my task definition - this is a simple AWS::ECS::TaskDefinition to host strapi using Fargate:
Environment:
- Name: NODE_ENV
Value: !Ref Environment
- Name: CORS_ALLOWED_ORIGINS
Value: !Sub "[https://www.${DomainAddress}, https://${ApiDomainAddress}]"
- Name: DATABASE_NAME
Value: !Sub "strapi_${Environment}"
- Name: DATABASE_PORT
Value: !Ref DatabasePort
- Name: DATABASE_HOST
Value: !GetAtt DBInstance.Endpoint.Address
- Name: DATABASE_USERNAME
Value: !Sub "{{resolve:secretsmanager:${RDSInstanceRotationSecret}::username}}"
- Name: DATABASE_PASSWORD
Value: !Sub "{{resolve:secretsmanager:${RDSInstanceRotationSecret}::password}}"
- Name: UPLOAD_AWS_BUCKET_NAME
Value: !Ref StrapiImageUploadBucket
- Name: UPLOAD_MEDIA_SOURCE
Value: !Sub "['self', data:, blob:, dl.airtable.com, ${StrapiImageUploadBucket.RegionalDomainName}]"
- Name: UPLOAD_IMAGE_PROVIDER
Value: !Ref UploadImageProvider
The main thing to consider is that the AWS credentials and region are read from the Task’s AWS::IAM::Role so I don’t pass these into the task itself. The bucket declaration itself is a very basic AWS::S3::Bucket with mostly the default configuration. See below:
StrapiImageUploadBucket:
Type: AWS::S3::Bucket
DeletionPolicy: Delete
Properties:
BucketName: !Sub "${ServiceName}-strapi-image"
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: "AES256"
LifecycleConfiguration:
Rules:
- Id: !Sub "${ServiceName}-strapi-image"
NoncurrentVersionExpirationInDays: !Ref BucketLifecycleRetention
Status: Enabled
Happy to provide any help or further examples should anybody require these.
Cheers