January 21, 2012

Blogging with Jekyll + S3 + CloudFront

When I decided to power this blog with Jekyll, it took me a while to figure out a good way to host and configure it. I thought explaining my setup might be helpful for others who are getting started with Jekyll.

If you have a blog but haven’t heard of Jekyll, you should check it out. It’s great for anyone who likes writing in the text editor of their choice instead of some web interface, wants to store their work in Dropbox or version control, and is comfortable running a few Terminal commands.

Why S3?

I initially started out hosting my blog on GitHub Pages, which is a free service offered by GitHub for hosting a Jekyll blog stored in Git. The price is certainly right, but there were a couple problems.

First, GitHub Pages experienced some downtime while I was setting up my blog, and I feel strongly about having good blog uptime. Second, if you don’t have a paid GitHub account ($7/month+) the repository containing your blog is accessible to the world, including drafts and unpublished posts.

An alternative is using Amazon S3, Amazon’s cloud file storage service. Amazon lets you host a static website on S3 with your own domain name. You can also easily use Amazon CloudFront with S3. CloudFront is a CDN (content distribution network) that serves your content from a worldwide server network and helps to make your website faster.

Setting up S3 and CloudFront

If you’ve never used Amazon Web Services before, it can be a little confusing to get started. First, you need to sign up for an AWS account. When you have your account, log into the AWS Management Console and head to the S3 tab. Then:

  1. Create a bucket called www.yourdomain.com. One minor downside to S3 is you can’t use yourdomain.com – you have to use some subdomain like www or blog. I’ll talk about this more below.

  2. Under the properties for this bucket, you’ll need to go to the Website tab, check the box to enable static web hosting, and set your index and error documents. Your index document should probably be index.html. Your error document is another HTML page for file not found (404) errors.

  3. Make a note of your endpoint (mine is http://www.maxmasnick.com.s3-website-us-east-1.amazonaws.com/). You’ll need it below.

  4. On the permissions tab, create a bucket policy. You can copy mine and just change the bucket name.

You can go ahead and enable CloudFront now too. Head over to the CloudFront tab, and create a new Distribution for the S3 bucket you just created. This will mirror your S3 bucket on CloudFront – for example, http://d2lazzs3blj336.cloudfront.net/index.html shows the home page of my website exactly* as it appears on S3.

* CloudFront will cache the contents of your S3 bucket for up to 24 hours. This cache is created from S3 the first time someone hits an asset under your CloudFront URL. This means that CloudFront won’t necessarily reflect changes on S3 immediately. You can manually expire objects in CloudFront, but it’s easier to just not use it for anything that will change frequently.

Setting up your DNS

You’ll need to create some DNS records to use your own domain with S3. The way you do this depends on your DNS provider (I use Zerigo, which is cheap, reliable, and easy to use). At a minimum, you’ll need to follow your DNS provider’s instructions to create a CNAME pointing www.yourdomain.com at your S3 endpoint.

Zerigo lets you create a redirect from yourdomain.com to www.yourdomain.com – you can’t use a CNAME on a bare domain. You can set up a redirect with Apache if your DNS provider doesn’t do redirects.

You can also create a CNAME for your CloudFront endpoint. I use cdn.maxmasnick.com for this.

Getting your Jekyll site onto S3

There’s a great command line tool called s3cmd that acts like rsync for S3. It makes it easy to upload your Jekyll site onto S3, and after your initial upload s3cmd will only upload file that have changed. If you’re on Mac, you can use Homebrew to install s3cmd by running brew install s3cmd.

I created a file called publish.sh in my Jekyll folder so I can run jekyll && ./publish.sh to publish to S3. publish.sh only has one line in it:

s3cmd sync --delete-removed _site/ s3://www.maxmasnick.com/ --verbose

If you haven’t used s3cmd before, you can set it up with your access keys by running s3cmd --configure. You can get these access keys off the Security Credentials portion of the AWS website.

Jekyll configuration for CloudFront

To make it easy to serve my assets from CloudFront, I set up a custom Liquid filter:

module Jekyll
  module AssetFilter
    def cdn(input)
      "[email protected][:site].config['cdn']}/#{input}"
    end
  end
end

Liquid::Template.register_filter(Jekyll::AssetFilter)

Save this in _plugins/cdn.rb off the root of your Jekyll site’s directory.

Then I added a CDN entry to my _config.yml file. If I comment this line out, my assets will be served off of S3 (or localhost if I’m running Jekyll locally).

cdn: http://cdn.maxmasnick.com

Whenever I want an asset to be served by the CDN, I pass it through this Liquid filter. For example, in my layout file I have: {% assign special = ‘{{ “assets/css/frameless.css” | cdn }}’ %}

<link rel="stylesheet" href="{{ special }}" />

Alternatives

I like hosting on S3 because it’s reliable (S3 is “designed to provide 99.999999999% durability and 99.99% availability of objects over a given year”) and cheap (I served more than 20,000 pageviews for less than $1 this January).

However, there are alternatives for hosting static sites. As I mentioned above, GitHub Pages is free and works pretty well. You can also host a static site on Heroku (for example, see this great post on hosting a static blog on Heroku + Google App Engine).

If you’re looking for alternatives to Jekyll, I wrote about the different options.


Comments? Please send me a message.

Subscribe via RSS or email.