In this article we will: Create a bucket in s3 with CDK, setup the bucket to allow hosting, set the default document, deploy a sample HTML file to the bucket, look up a root hosted zone, create a new DNS record in an existing zone that points to a s3 bucket.
Introduction
Use AWS CDK to deploy a S3 bucket and use 53 to point DNS to the site!
Requirements
CDK, S3 and Route53
Static sites are common place, often I'll knock something up as a proof of concept and to share that with my friends I'll make a public s3 bucket and send the link, quick and easy. If I need/want this for a longer period of time I typically create a sub domain and point that to the bucket.
In this example we will:
- Create a bucket in s3 with CDK
- Setup the bucket to allow hosting
- Set the default document
- Deploy a sample html file to the bucket
- Look up a root hosted zone
- Create a new DNS record in an existing zone that points to a s3 bucket
mkdir bucket.website.com
cd bucket.website.com
cdk init app --language typescript
npm install @aws-cdk/aws-s3 --save-dev
npm install @aws-cdk/aws-s3-deployment --save-dev
npm install @aws-cdk/aws-route53 --save-dev
We are now ready to code. Let's begin creating the files and folders.
# Create a folder for the Program, this is my convention the program may
# have more parts, for now it's just static so creat just those folders
mkdir -p Program/static
# Populate the index.html file with some content
echo "S3 Hosting with CDK" > Program/static/index.html
Our example Program is ready for some infrastructure.
Open "lib/{stack-name}.ts" and let's build it.
This is very straight forward, remeber when createing buckets that the bucket name should match the domain name you intend to point at the bucket.
const publicAssets = new s3.Bucket(this, 'example-qr', {
bucketName: 'example.url2qr.me',
publicReadAccess: true,
removalPolicy: cdk.RemovalPolicy.DESTROY,
websiteIndexDocument: 'index.html',
});
Be aware that although the removalPolicy
is set to destroy, when deleting this stack this will fail unless you remove the files in the bucket. If the bucket is empty when the stack is deleted the bucket will also be deleted.
Deploy the static code to the bucket.
const deployment = new s3Deployment.BucketDeployment(
this,
'deployStaticWebsite',
{
sources: [s3Deployment.Source.asset('./program/static')],
destinationBucket: publicAssets,
}
);
I have an existing zone I want to add a subdomain to ( url2qr.me ). The first step is to look this up. You can look this up by hostZoneId
or zoneName
. For readability here I have used domain name. [Docs]
const zone = route53.HostedZone.fromLookup(this, 'baseZone', {
domainName: 'url2qr.me'
});
Next we create a new entry in Route53
and point the entry to the "bucketWebsiteDomainName
" of the s3 bucket we created. In this example it's "example.url2qr.me".
const cName = new route53.CnameRecord(this, 'test.baseZone', {
zone: zone,
recordName: 'example',
domainName: publicAssets.bucketWebsiteDomainName
});
The complete code should look like so:
import * as cdk from '@aws-cdk/core';
import * as s3 from '@aws-cdk/aws-s3';
import * as s3Deployment from '@aws-cdk/aws-s3-deployment';
import * as route53 from '@aws-cdk/aws-route53';
export class AwsCdkS3Stack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const publicAssets = new s3.Bucket(this, 'example-qr', {
bucketName: 'example.url2qr.me',
publicReadAccess: true,
removalPolicy: cdk.RemovalPolicy.DESTROY,
websiteIndexDocument: 'index.html',
});
const deployment = new s3Deployment.BucketDeployment(
this,
'deployStaticWebsite',
{
sources: [s3Deployment.Source.asset('./program/static')],
destinationBucket: publicAssets,
}
);
const zone = route53.HostedZone.fromLookup(this, 'baseZone', {
domainName: 'url2qr.me'
});
const cName = new route53.CnameRecord(this, 'test.baseZone', {
zone: zone,
recordName: 'example',
domainName: publicAssets.bucketWebsiteDomainName
});
}
}
We will also have to pass in the accountID
and default region. Open "bin/{stackname}.ts" and set the values. I have them set as env variables, you can hard code them for example purpose aswell
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from '@aws-cdk/core';
import { AwsCdkS3Stack } from '../lib/aws-cdk-s3-stack';
const app = new cdk.App();
new AwsCdkS3Stack(app, 'AwsCdkS3Stack', {
env: {
account: process.env.CDK_DEFAULT_ACCOUNT,
region: process.env.CDK_DEFAULT_REGION
}
});
We are ready to deploy
cdk bootstrap
cdk deploy
Once complete run:
curl example.url2me.com
and we should see the contents of the index.html file.
On in a browser.
Full Repo here: https://github.com/kukielp/aws-cdk-s3