HOWTO: Serve Angular app from S3 and CloudFront with free HTTPS

There are quite a few posts out there that try to explain how to set up S3 and CloudFront to serve up your single page Angular2 app. However, they are incomplete, lead you into more configuration than is necessary and/or don’t do what I think is best practice.

In the end you will have a lightning fast SECURE page, with fortune 500 reliability and durability – all for cheaper than you will believe.

Step 1: Register your domain(s) and create SSL cert via ACM

I highly recommend using AWS Route53 to register your domains. It’s $10/year for .com’s with no bullshit price changes or coupon hunting. Super easy to use and gives you lots of easy integration with other AWS services like CloudFront, EC2, ELB, S3 etc.

For this example we pretend I registered rynop.org and rynop.com

Next go to the Amazon Certificate Manager (ACM) console page and request a certificate. Put in your root apex(es) (aka naked domain) and all your subdomains. ACM SSL certs are FREE and they auto-renew. It’s similar to letsencrypt but zero overhead. Ex:

rynop.org, *.rynop.org, rynop.com, *.rynop.com

You will get an email to your domain admin contact email addresses to approve.

Step 2: Create S3 bucket and upload hello world HTML page

Create an s3 bucket (Ex: http://www.rynop.com). Create a file named index.html with the following contents. When you upload the file make sure to give it public read permissions.

Note: you will notice I did NOT setup static website hosting on my S3 bucket. It is not needed as CloudFront will handle it all for you.

Step 3: Create and set up CloudFront distribution

Create a new CloudFront distribution, specify the “web” delivery method.

Alternate Domain Names:http://www.rynop.com. I omitted the root apex domains as we are going to setup another CloudFront distro in to redirect those to http://www.rynop.com. Don’t do naked domains over HTTPS. Google this if you care why.

SSL Certificate:Custom SSL Certificate. Chose the cert you created in ACM

Default Root Object:index.html. This is your Angular2 app entry point

Click Create Distribution. Then immediately go back and edit your CF distro. Choose the Error Pages Tab and press Create Custom Error Response. Fill in the fields like this for BOTH 403 and 404 errors:

This will now support when a URL change is emulated via pushState or directly navigated to when you type in your browser address bar.

Step 4: Point your DNS to CloudFront distribution

Route53 makes this dead simple. Create a new record set (ex: http://www.rynop.com), type of “A”, alias “yes” and find your CloudFront distro DNS name. If it doesn’t auto-populate you can get the DNS name from the CloudFront web UI. It will be something like dsjaaauazh42i.cloudfront.net.

Alternate Domain Names
(CNAMEs) put all the domains you want to re-direct.

Click “Create distribution”. This will take about 20 minutes.

Now go back into Route53, and create “A” record set of type “alias” for each domain that needs to be re-directed. Select the CloudFront Distribution from the “alias target” dropdown. It may take a while to populate. If it does not populate after refreshing, copy the domain name for the CloudFront distribution from the CloudFront console, and use it as the value for “Alias Target”.

I created A record set aliases for rynop.com,rynop.org,www.rynop.org

Step 6: Verify SSL and re-direction

You can now validate the re-direct by runningcurl -v "http://rynop.com"

You should get a 301 re-direct.

You can then put any of the domains you configured in your web browser and you should see the hello world html page.

Step 7: Compress and upload your Angular2 app

Angular build does a great job of creating your Angular static assets.

I highly recommend gzipping your assets BEFORE uploading to s3. CloudFront supports runtime gzipping however CloudFront will not gzip if its busy. All the consumers of your website have supported gzip compression for the last 15 years so you don’t have to worry about the Very: header.

With this in mind I created the following script that handles upload to S3 with CloudFront in mind:

I then call this script from yarn, by defining the following in my package.json, scripts section:

All you have to do is replace my bucketname in deploy:prod with the bucketname that hosts your Angular app. Note: you must install gzip-all as a development dependency.

Summary

You now have a single page app, who’s static assets have full HTTP/2 support, 11 nines of durability, infinite scale, free SSL, cached at the edge all over the world with zero servers to maintain and no ongoing renewals. You are ONLY charged for bandwidth and HTTP requests out of CloudFront (and the infrequent calls to your S3 origin).

Lots of setup here I know, but remember this is one time only and you are getting some world class features for almost nothing.

Next steps

If you’d like this all in a nice package, deployable via CloudFormation, check out my AWS Blueprint for an Angular app. It has most of this, plus much more – like easy deployment.