This is an AWS CDK v2 construct library for deploying a single-page website with S3, CloudFront, Route 53, and ACM. CreateCloudfrontSite is the recommended construct because it uses a private S3 origin with CloudFront Origin Access Control (OAC), while CreateBasicSite is deprecated because it creates a public S3 website endpoint.
Creates a website using a private S3 bucket, a CloudFront distribution, and DNS records in Route 53.
yarn add cdk-simplewebsite-deployimport * as cdk from 'aws-cdk-lib';
import { CreateCloudfrontSite } from 'cdk-simplewebsite-deploy';
import { Construct } from 'constructs';
export class PipelineStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
new CreateCloudfrontSite(this, 'test-website', {
websiteFolder: './src/dist',
indexDoc: 'index.html',
hostedZone: 'example.com',
subDomain: 'www.example.com',
});
}
}<dependency>
<groupId>com.thonbecker.simplewebsitedeploy</groupId>
<artifactId>cdk-simplewebsite-deploy</artifactId>
<version>0.4.2</version>
</dependency>package com.myorg;
import com.thonbecker.simplewebsitedeploy.CreateCloudfrontSite;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
import software.constructs.Construct;
public class MyProjectStack extends Stack {
public MyProjectStack(final Construct scope, final String id) {
this(scope, id, null);
}
public MyProjectStack(final Construct scope, final String id, final StackProps props) {
super(scope, id, props);
CreateCloudfrontSite.Builder.create(this, "test-website")
.websiteFolder("./src/build")
.indexDoc("index.html")
.hostedZone("example.com")
.subDomain("www.example.com")
.build();
}
}pip install cdk-simplewebsite-deployfrom aws_cdk import Stack
from cdk_simplewebsite_deploy import CreateCloudfrontSite
from constructs import Construct
class MyProjectStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
CreateCloudfrontSite(self, 'test-website', website_folder='./src/build',
index_doc='index.html',
hosted_zone='example.com',
sub_domain='www.example.com')Use CreateCloudfrontSite for new sites. CreateBasicSite configures public bucket access so Route 53 can alias directly to the S3 website endpoint.
yarn add cdk-simplewebsite-deployimport * as cdk from 'aws-cdk-lib';
import { CreateBasicSite } from 'cdk-simplewebsite-deploy';
import { Construct } from 'constructs';
export class PipelineStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
new CreateBasicSite(this, 'test-website', {
websiteFolder: './src/build',
indexDoc: 'index.html',
hostedZone: 'example.com',
});
}
}<dependency>
<groupId>com.thonbecker.simplewebsitedeploy</groupId>
<artifactId>cdk-simplewebsite-deploy</artifactId>
<version>0.4.2</version>
</dependency>package com.myorg;
import com.thonbecker.simplewebsitedeploy.CreateBasicSite;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
import software.constructs.Construct;
public class MyProjectStack extends Stack {
public MyProjectStack(final Construct scope, final String id) {
this(scope, id, null);
}
public MyProjectStack(final Construct scope, final String id, final StackProps props) {
super(scope, id, props);
CreateBasicSite.Builder.create(this, "test-website")
.websiteFolder("./src/build")
.indexDoc("index.html")
.hostedZone("example.com")
.build();
}
}pip install cdk-simplewebsite-deployfrom aws_cdk import Stack
from cdk_simplewebsite_deploy import CreateBasicSite
from constructs import Construct
class MyProjectStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
CreateBasicSite(self, 'test-website', website_folder='./src/build',
index_doc='index.html',
hosted_zone='example.com')The CreateCloudfrontSite construct includes optional advanced features for security, performance, and monitoring.
Enable comprehensive security headers including HSTS, X-Frame-Options, Content-Type-Options, and XSS protection:
new CreateCloudfrontSite(this, 'secure-website', {
websiteFolder: './src/dist',
indexDoc: 'index.html',
hostedZone: 'example.com',
enableSecurityHeaders: true, // π Adds security headers
});Enable IPv6 connectivity with AAAA records:
new CreateCloudfrontSite(this, 'ipv6-website', {
websiteFolder: './src/dist',
indexDoc: 'index.html',
hostedZone: 'example.com',
enableIpv6: true, // π Adds AAAA records for IPv6
});Enable CloudFront access logging for analytics and monitoring:
new CreateCloudfrontSite(this, 'logged-website', {
websiteFolder: './src/dist',
indexDoc: 'index.html',
hostedZone: 'example.com',
enableLogging: true, // π Enables access logging
// logsBucket: myCustomBucket, // Optional: use existing bucket
});Integrate with AWS WAF for enhanced security:
new CreateCloudfrontSite(this, 'waf-protected-website', {
websiteFolder: './src/dist',
indexDoc: 'index.html',
hostedZone: 'example.com',
webAclId: 'arn:aws:wafv2:us-east-1:123456789012:global/webacl/my-web-acl/12345678-1234-1234-1234-123456789012', // π‘οΈ WAF protection
});Grant additional OAC permissions to the website bucket. This can be useful when you need CloudFront to distinguish missing objects from access-denied responses.
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
new CreateCloudfrontSite(this, 'website-with-list-access', {
websiteFolder: './src/dist',
indexDoc: 'index.html',
hostedZone: 'example.com',
originAccessLevels: [
cloudfront.AccessLevel.READ,
cloudfront.AccessLevel.LIST,
],
});Attach CloudFront Functions to the default behavior for lightweight viewer request or viewer response logic.
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
const rewriteFunction = new cloudfront.Function(this, 'RewriteFunction', {
code: cloudfront.FunctionCode.fromInline(
'function handler(event) { return event.request; }',
),
});
new CreateCloudfrontSite(this, 'website-with-function', {
websiteFolder: './src/dist',
indexDoc: 'index.html',
hostedZone: 'example.com',
functionAssociations: [
{
eventType: cloudfront.FunctionEventType.VIEWER_REQUEST,
function: rewriteFunction,
},
],
});Add custom cache behaviors for different content types:
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
new CreateCloudfrontSite(this, 'optimized-website', {
websiteFolder: './src/dist',
indexDoc: 'index.html',
hostedZone: 'example.com',
additionalBehaviors: {
'/api/*': {
origin: myApiOrigin,
allowedMethods: cloudfront.AllowedMethods.ALLOW_ALL,
cachePolicy: cloudfront.CachePolicy.CACHING_DISABLED,
},
'/static/*': {
cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED_FOR_UNCOMPRESSED_OBJECTS,
},
}, // β‘ Custom caching strategies
});Define custom error handling:
new CreateCloudfrontSite(this, 'custom-errors-website', {
websiteFolder: './src/dist',
indexDoc: 'index.html',
hostedZone: 'example.com',
customErrorResponses: [
{
httpStatus: 404,
responseHttpStatus: 200,
responsePagePath: '/index.html', // SPA routing
},
{
httpStatus: 403,
responseHttpStatus: 200,
responsePagePath: '/index.html',
},
], // π― Custom error handling
});import * as cdk from 'aws-cdk-lib';
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
import { CreateCloudfrontSite } from 'cdk-simplewebsite-deploy';
import { Construct } from 'constructs';
export class AdvancedWebsiteStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const rewriteFunction = new cloudfront.Function(this, 'RewriteFunction', {
code: cloudfront.FunctionCode.fromInline(
'function handler(event) { return event.request; }',
),
});
new CreateCloudfrontSite(this, 'advanced-website', {
websiteFolder: './dist',
indexDoc: 'index.html',
errorDoc: 'error.html',
hostedZone: 'example.com',
subDomain: 'www.example.com',
// Performance & Security
priceClass: cloudfront.PriceClass.PRICE_CLASS_ALL,
enableSecurityHeaders: true,
enableIpv6: true,
originAccessLevels: [
cloudfront.AccessLevel.READ,
cloudfront.AccessLevel.LIST,
],
// Monitoring & Protection
enableLogging: true,
webAclId: 'arn:aws:wafv2:us-east-1:123456789012:global/webacl/my-web-acl/12345678-1234-1234-1234-123456789012',
// Custom Behaviors
additionalBehaviors: {
'/api/*': {
allowedMethods: cloudfront.AllowedMethods.ALLOW_ALL,
cachePolicy: cloudfront.CachePolicy.CACHING_DISABLED,
},
},
// Edge Logic
functionAssociations: [
{
eventType: cloudfront.FunctionEventType.VIEWER_REQUEST,
function: rewriteFunction,
},
],
// SPA Error Handling
customErrorResponses: [
{
httpStatus: 404,
responseHttpStatus: 200,
responsePagePath: '/index.html',
},
],
});
}
}- Security Headers: Automatic HSTS, X-Frame-Options, Content-Type-Options, and XSS protection
- WAF Integration: Support for AWS WAF Web ACLs for advanced threat protection
- Origin Access Control: Modern S3 bucket protection (replaces deprecated OAI)
- Configurable OAC Permissions: Optional origin access levels for the website bucket
- Smart Caching: Optimized cache policies for better performance
- HTTP/2 & HTTP/3: Latest protocol support for faster loading
- Global Edge Locations: Configurable price classes for worldwide distribution
- IPv6 Support: Dual-stack networking for better connectivity
- CloudFront Functions: Optional viewer request and response function associations
- Access Logging: CloudFront access logs for analytics
- Custom Error Handling: Flexible error response configuration
- SPA Support: Built-in single-page application routing support
- Backward Compatible: All existing configurations continue to work
- Type Safe: Full TypeScript support with comprehensive interfaces
- CDK v2 Ready: Built for the latest AWS CDK version
- Multi-Language: Support for TypeScript, Python, and Java
Distributed under the Apache-2.0 license.