Using free SSL and Cloudfront for an Angular React site
Hold on Cowboy
This blog post is pretty old. Be careful with the information you find in here. It's likely dead, dying, or wildly inaccurate.
This is the holy grail, the culmination of knowing there is something out there better, stronger, faster. In this blog post, I’ll outline how to set up Amazon S3, Cloudfront, and Route53 to serve your static React, Angular, or any site over HTTPS. Get ready, it’s about to get real.
What am I even talking about?
The new en vogue way to build sites is to use React or Angular on the front end. Compile the site into a few files, like index.html
, scripts.js
, styles.css
using Webpack. Then you take those files and upload them to a some basic web server (no need for Node.js, Rails, or other dynamic scripting language server). I’ve used https://surge.sh/, which is really easy and customizable, but you’ll need to pay $13 a month for a custom SSL site. For hobby sites, that gets to add up.
Since Google will start pointing out non-HTTPS sites, it’s probably a good idea to get all your sites secure, even the static ones. Most places charge for SSL, but Amazon is offering Free HTTPS certs for its services. This means you can use free certs for Cloudfront and Elastic Loadbalancers.
Cloudfront just serves up files in your Amazon S3 bucket. The last piece is using Route53 to point your domain to Cloudfront, but that’s not really required.
+----------+ +-----------+ +-----------+
| Route | | | | |
www.example.com+--> 53 +--> Cloudfront+--> S3 |
| | | | | |
| | | | | |
+----------+ +-----------+ +-----------+
Setting up the site on Amazon S3
Get Amazon S3 to act as our web server
The first step involves setting up an Amazon S3 bucket to hold our files. It’s a good idea to name the bucket after your site, e.g. www.example.com
. You’ll need to set the properties for the bucket.
Permissions :: Bucket Policy You’ll need to set these custom bucket policy permissions. Basically, anyone can get any object, and anyone can list the bucket contents.
{
"Version": "2012-10-17",
"Id": "Policy1455417919361",
"Statement": [
{
"Sid": "Stmt1455417914563",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::www.example.com"
},
{
"Sid": "Stmt1455417914543",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::www.example.com/*"
}
]
}
Static Website Hosting Select Enable Website Hosting, for the Index Document: index.html
. Do the same for Error Document: index.html
. This is required, because we are using html5 history and a user may try to fetch https://www.example.com/app/users
, since this file doesn’t really exist, we still want to serve up our React/Angular app. Just to be clear, our app URLs will NOT be using hasbang-urls.
Now would be a good time to upload your static app files to your new bucket. Here is an example I used for testing, notice how I am placing a ?v=2
version. This will allow our Cloudfront cache to differentiate between versions. It’s beyond the scope of this post, but Webpack can easily version bundles and update your HTML file.
index.html
<html>
<head>
<link rel="stylesheet" href="/style.css?v=2" type="text/css" media="screen" title="no title" charset="utf-8">
</head>
<body>
<h1>Example Site</h1>
</body>
</html>
style.css
h1 {
color: red;
}
Get a free SSL cert
Other places charge as much as $20/month for cert support
This one is not that hard. Go to the Certificate Manager and set up an ssl cert for your domain e.g. example.com
& www.example.com
. You’ll need to be able to response to a select number of email aliases, so you’ll need to have access to the domain and the email server for the domain.
Cache with Cloudfront
Use Cloudfront as a sort of loadbalancer/SSL frontend to S3
Now we come to the part of the show where it gets intense. Cloudfront has a number of options, most of the defaults are pretty sane, but let’s list out what we need to do. First we’re going to create a new web distribution.
- Origin Domain Name: Your bucket, you can select it from the list
- Viewer Protocol Policy: Redirect HTTP to HTTPS
- Forward Query Strings: Yes
- Price Class: I choose US / Europe, you choose whatever
- Alternate Domain Names: www.example.com
- SSL Certificate: Custom SSL Cert (choose your newly created cert)
- Default Root Object: index.html
- Click Create Distribution
Wait, we’re not done yet. We need to tell Cloudfront that when we get an error, that we need to serve up the index.html
file. Click on your distribution, then click on the Error Pages tab. Now it’s time to click Create Custom Error Response. From here you’ll select
- HTTP Error Code: 404
- Customize Error Response: Yes
- Response Page Path: index.html
- HTTP Response Code: 200
That will serve up the index.html
file whenever Cloudfront can’t find the file.
Route53 points to Cloudfront (optional)
Route traffic for www.example.com to Cloudfront
Now you can create a record in our domain for your Cloudfront endpoint. Go to your Hosted Zones in Route53. From there Create Record Set. The Name: www, Alias: Yes, Alias Target: your Cloudfront url. Save it and you’re done. Now after a little bit, when your Cloudfront distribution is done processing, you should be able to hit your site in a browser and see it served up.
Updating your site
You need to invalidate the cached
index.html
If you update your CSS file, you’ll need to bump the ?v=2
to ?v=3
(or have Webpack just build your site and do it for you). You can then upload your files to your Bucket (please automate this). Then you’ll need to invalidate at the very least, the index.html
file on Cloudfront. Go to your Cloudfront distribution and select the Invalidations tab and Create Invalidation. You can do every file with *
, or just put in /index.html
to clear the index.html file. After a few minutes, the new version of index.html will start to be served up by Cloudfront.
You’ve just created a free, SSL protected, web server that is blazing fast, inexpensive, and supports cutting edge ReactJS, Angular, and even Ember web apps. Go forth and obtain knowledge and wisdom. Please leave a comment or contact me on Twitter.