If you are using a static site builder like Jekyll, Amazon S3 is one of the cheapest hosting solutions around. To speed up delivery time for a little extra cost, I recommend using Cloudfront in front of S3.
A few months ago I decided to serve my static assets from S3, but yesterday I decided to take the full jump. Here is what I did to make the move.
This full guide will be most useful for static sites on existing hosting solutions that you are moving to AWS while using outside DNS services. This guide uses s3_website, Amazon S3, Amazon Cloudfront, and a non-Amazon DNS service.
If you are setting up a site from scratch, use Amazon’s guide instead.
0. Back up your stuff
The steps below worked for me, but I can’t guarantee everything will work for you. Back up your stuff so you can roll back. You’ve been warned.
Really, before you make a mistake and mess a bunch of stuff up, make sure you have a back up of everything:
- Your local Jekyll site
- The content on your existing webserver
- Screenshots of your current DNS settings
1. Set up your AWS account
Set up an account at Amazon Web Services.
2. Download and configure s3_website
s3_website is a very useful tool for automatically setting up buckets on S3 and a Cloudfront distribution to host a static site. It also helps easily deploy updates to your static site with a few commands.
Follow the tool’s instructions on Github.
- Run
s3_website cfg create
. This generates a configuration file called s3_website.yml. - You’ll need to make an AWS user for the tool with access keys and set your
configurations in the
s3_website.yml
file. - Run
s3_website cfg apply
. This will configure your bucket to function as an S3 website. If the bucket does not exist, the command will create it for you. When you run this, it will ask you whether you want to deliver your website via CloudFront. If you answer yes, the command will create a CloudFront distribution for you.
Handling non-Jekyll content
If you have content on your webserver that doesn’t exist in your Jekyll site,
you’ll need to set some extra configurations for those things in the
s3_website.yml
. For example, I serve a
bunch of PDFs
that are separate from my actual Jekyll instance. If you do, too, make sure you
take advantage of the ignore_on_server
section of the configuration. Make sure
to uncomment it (remove the #
in front of it) and list the folder paths from
the root that you want the tool to ignore on the server. Otherwise folders not
on this list and not in your Jekyll site will be removed.
I added these:
ignore_on_server:
- justanswer
- illum
Reminder: Don’t use tabs for formatting in YAML files. Use spaces.
3. Deploy your website using s3_website
Run a new build on your Jekyll site: jekyll build
Then, push up to the AWS environment: s3_website push
Don’t worry, even though the s3_website.yml
gets added to your _site
folder,
it won’t get uploaded to S3. The tool skips it. I triple checked this because I
didn’t want to publish my access keys online.
Wait 15 or 20 minutes for your site to propagate across Cloudfront (the
Cloudfront dashboard shows the
propagation status.) Once it does, check your Cloudfront domain (or public S3
domain if you aren’t using Cloudfront). The s3_website tool gives you both
domains during your initial setup, or you can always get them from your
AWS console at any time. For example, my
Cloudfront domain for this site is d27zm8z2abfvhn.cloudfront.net
and my S3
domain is http://cagrimmett-jekyll.s3-website-us-east-1.amazonaws.com
.
Check the domains and make sure everything seems to be live and working correctly.
4. Add your own domain to Cloudfront or S3
First, add your domain, including the www, as a CNAME on your Cloudfront distribution. This allows Cloudfront to serve requests to this domain once it is point there. This is the easy part.
Pointing your domain at Cloudfront without using Route 53 as your DNS provider
I have a bunch of DNS records on cagrimmett.com, so I didn’t want to migrate my DNS over to Amazon’s Route 53. That means I had an hour of trial and error (as well as a consultation from my friend Eric Davis) figuring out how to get things to work. Also, the typical A record pointing won’t work because the IP addresses to Amazon’s servers change regularly.
The solution we settled on is: CNAME the www
subdomain to Cloudfront and
forward all cagrimmett.com
requests to www.cagrimmett.com
.
To CNAME your www
subdomain to Cloudfront, just log in to your DNS service and
add a new CNAME record for www (or change the existing one if you have it) and
point it to your Cloudfront domain, which is the one that looks like this:
d27zm8z2abfvhn.cloudfront.net.
You have two options for forwarding non-www requests to the www subdomain:
A) If you aren’t using your domain for anything except this site, you can use
your DNS service’s domain forwarding tool if it has one. Set it up to forward
domain.com
to http://www.domain.com
. Note: If you are using your domain for
anything else or if any subdomains point to the @ record, don’t use this option.
I tried this and took down my other sites, which are served from subdomains of
cagrimmett.com.
B) Use Apache or nginx to rewrite requests. This means that you still need your
original hosting, but it will only be used to rewrite your domain requests. This
isn’t an issue for me because I still need my hosting to serve
cooklikechuck.com, amandakate.me, and my dev and staging areas for WordPress
development. This option isn’t ideal, and definitely not what I would have
designed from the beginning, but I don’t want to burn everything down and start
over. So Apache it is. Here is what my rewrite rule looks like in my .htaccess
file:
RewriteEngine On
RewriteRule ^(.*) http://www.cagrimmett.com/$1 [QSA,NC,NE,R,L]
This takes any non-www requests and rewrites them to the www subdomain, preserving the whole query string, making sure existing links to your content around the web don’t break.
Wait an hour for all changes to take affect and you should be good to go!
5. Deploying updates
Since we used s3_website, deploying updates and new posts to your site will be super easy:
Navigate to your Jekyll site folder and build your Jekyll site: jekyll build
Then push up to the AWS environment: s3_website push
That’s all!
A note on SSL
I opted to not use SSL for my site right now because there are a ton of extra steps and extra cost involved. I’ll probably revisit this later when Google starts penalizing non-secure sites, but for the time being I’m sticking with plain http. I’m not collecting any user-submitted data.