Skip to content

Instantly share code, notes, and snippets.

@davideicardi
Created October 17, 2023 23:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save davideicardi/1c4b2849078766dc659afa6ab67034a7 to your computer and use it in GitHub Desktop.
Save davideicardi/1c4b2849078766dc659afa6ab67034a7 to your computer and use it in GitHub Desktop.
AWS CDK Static Web Site stack from S3 with CloudFront and custom domain
import { Bucket } from 'aws-cdk-lib/aws-s3';
import { BucketDeployment, Source } from 'aws-cdk-lib/aws-s3-deployment';
import { CloudFrontWebDistribution, OriginProtocolPolicy } from 'aws-cdk-lib/aws-cloudfront';
import { ARecord, HostedZone, RecordTarget } from 'aws-cdk-lib/aws-route53';
import { CloudFrontTarget } from 'aws-cdk-lib/aws-route53-targets';
import { Construct } from 'constructs';
import { aws_s3 } from 'aws-cdk-lib';
interface StaticWebsiteProps {
domainName: string;
hostedZoneId: string;
sourceFolder: string; // relative path to the website source folder, like './out'
certificateArn: string;
}
export class StaticWebsiteSubStack {
constructor(
scope: Construct,
id: string,
props: StaticWebsiteProps,
) {
const websiteBucket = new Bucket(scope, `${id}-bucket`, {
websiteIndexDocument: 'index.html',
websiteErrorDocument: 'error.html',
publicReadAccess: true,
// Cause of the issue https://github.com/aws/aws-cdk/issues/25983
// we've used the following workaround:
// https://stackoverflow.com/questions/56045776/aws-cdk-s3putbucketpolicy-access-denied-when-deploying-bucket-with-public-read
blockPublicAccess: aws_s3.BlockPublicAccess.BLOCK_ACLS,
accessControl: aws_s3.BucketAccessControl.BUCKET_OWNER_FULL_CONTROL,
});
const distribution = new CloudFrontWebDistribution(scope, `${id}-cloudfront-dist`, {
originConfigs: [
{
customOriginSource: {
domainName: websiteBucket.bucketWebsiteDomainName,
originProtocolPolicy: OriginProtocolPolicy.HTTP_ONLY,
},
behaviors: [{ isDefaultBehavior: true }],
},
],
viewerCertificate: {
aliases: [props.domainName],
props: {
acmCertificateArn: props.certificateArn,
sslSupportMethod: 'sni-only',
},
},
});
new BucketDeployment(scope, `${id}-bucket-deployment`, {
sources: [Source.asset(props.sourceFolder)],
destinationBucket: websiteBucket,
distribution: distribution, // invalidate distribution on deploy
});
const hostedZone = HostedZone.fromHostedZoneAttributes(scope, `${id}-hosted-zone`, {
hostedZoneId: props.hostedZoneId,
zoneName: props.domainName, // assuming the hosted zone is the same as the domain name
});
new ARecord(scope, `${id}-a-record`, {
zone: hostedZone,
recordName: props.domainName,
target: RecordTarget.fromAlias(new CloudFrontTarget(distribution)),
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment