AWS: Deploy a secure static website with CDN

AWS is a great choice for small-scale static web applications. This article illustrates the process to use AWS cloud services to serve a static website. Here I use https://joycoding.io as an example.

The features includes: static file storage (S3), CDN (CloudFront), HTTPS (Amazon Certificate Manager ACM) and domain name (Route 53).

S3

S3 stores static files including JavaScript, CSS, HTML, images, etc.

Important: do remember to set the customer header of the files.

Create New S3 Bucket

A bucket is a virtual space to store your static files. Go to AWS S3 service portal: https://s3.console.aws.amazon.com/s3/home?region=us-west-1 (change the region as you need). Click button Create bucket to create a bucket.

  1. Step 1 - Name and region: name it with your domain name, i.e., joycoding.io here.
  2. Step 2 - Configure options: leave it as default.
  3. Step 3 - uncheck Block all public access, to make this bucket accessible, as we want to make it a public website.
  4. Review and submit.

Then the bucket joycoding.io is created. Click it and edit its Permissions, go to tab Bucket Policy:

Selection 020

Edit the policy as below, click Save:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::joycoding.io/*"
        }
    ]
}

Go to the Properties tab, enable Static website hosting, choose Use this bucket to host a website, and click Save.

Finally, create another bucket named www.joycoding.io similarly. To points to note:

  1. for the policy, change the Resource value to "arn:aws:s3:::www.joycoding.io/*"
  2. do not enable Static website hosting.

OK. Now we are ready to send our code to the buckets.

Upload website files

Build your web app into some folder, such as build, like create-react-app I use:

  1. cd ~/Projects/joycoding.io && yarn build
  2. find build -type f -exec gzip -9 {} \; -exec mv {}.gz {} \;
  3. s3cmd put -m "application/json" *.json s3://joycoding.io/ && s3cmd put --add-header='Content-Encoding: gzip' -m "application/javascript" *.js s3://joycoding.io/ && s3cmd put -P index.html s3://joycoding.io/ && s3cmd put --add-header='Content-Encoding: gzip' -m "text/css" static/css/*.css s3://joycoding.io/static/css/ && s3cmd put --recursive static/* s3://joycoding.io/static/

Note: be sure to specify -m for the Content-type of a file. For CSS, it should be text/css, for JS, it should application/javascript. Otherwise, the files uploaded will be treated as plain text files. Alternatively, go to the AWS S3 portal, click your bucket, choose the file(s) you want to change Content-Type, click dropdown Actions and select Change metadata. Then you can change the content-type.

CloudFront

CloudFront provides CDN and HTTPS for a website.

Configure AWS CloudFront for CDN service. Click Create distribution, note:

  1. Select joycoding.io.s3... from the Origin Domain Name dropdown
  2. For Alternate Domain Names (CNAMES), type in www.joycoding.io [NEW_LINE] joycoding.io.
  3. To enable HTTPS, go to section SSL Certificate and choose Custom SSL Certificate (example.com), select a HTTPS certificate on the dropdown (you need to request a certificate beforehand).

You may encounter 404 problem if your app is Single-Page-Application:

Selection 022

If so, click the newly created CloudFront distribution, go to tab Error Pages. Click Create Custom Error Response and fill the form like:

Selection 025

Then click the button Create Custom Error Response again, choose HTTP Error Code 403, and other fields are the same as above.

Domain Name

Now we have an awesome website there, just need to give it a domain name. Buy or transfer your domain name at AWS S3: https://console.aws.amazon.com/route53/home?region=us-west-1#DomainListing. I have got one: joycoding.io.

So then, go to AWS Route 53 - Hosted zones, click Create Hosted Zone with domain name joycoding.io. Then click it to edit. Click Create Record Set to connect our S3 bucket to this domain name.

Selection 023

Note:

  1. Leave Name blank.
  2. Choose Yes for Alias.
  3. Choose the CloudFront instance named joycoding.io as Alias Target.

Do the same thing for www.joycoding.io.

ACM: HTTPS

HTTPS is almost the standard configuration for modern web applications. ACM is a service to provide Free certificates for your domain names. You can link it to your domain name easily.

Request a certificate

Go to AWS ACM to request a certificate for your domain.