Sören Bleikertz
20 Feb 2011

Jekyll with Amazon S3

Amazon recently announced that it is possible to host a static website completely from S3. I am using Jekyll in combination with git to deploy my website, and I was curious how to deploy this combination together with S3 static website hosting. In this blog post I will describe the necessary steps to achieve this.

Prerequisites

I tried this setup on Ubuntu 10.10 64bit, however I suppose it also works equally well on other distributions. I also assume you already have Jekyll (with git as the deployment method) and s3fs installed. Furthermore, the boto Python library for accessing AWS is initially required.

Setup S3 Bucket

You can follow this guide to setup a S3 bucket for serving a static website. Let’s say the name of the bucket is ‘mybucket’ for the rest of this setup guide.

Restricting S3 Access using IAM

Amazon’s Identity and Access Management (IAM) is useful to restrict the access for the website deployment script to the specific bucket holding the website. I used the following Python script to setup the user policy:

#!/usr/bin/env python
import boto

# almighty credentials
i = boto.connect_iam('accessKey', 'secretKey')

s3_policy = """
{
    "Statement":[{
        "Effect":"Allow",
        "Action":"s3:*",
        "Resource":[
            "arn:aws:s3:::mybucket",
            "arn:aws:s3:::mybucket/*"
        ]
    },
    {
        "Effect":"Allow",
        "Action":"s3:ListAllMyBuckets",
        "Resource":"arn:aws:s3:::*"
    }
    ]
}"""

response = i.create_user('jekyll')
response = i.put_user_policy('jekyll', 'mybucket-website',
    json.dumps(json.loads(s3_policy)))

response = i.create_access_key('jekyll')
access_key = response.access_key_id
secret_key = response.secret_access_key

print access_key, secret_key

Basically, the user jekyll will only have access to the bucket mybucket and it’s objects. However, in order to work with s3fs, the user also requires to issue the ListAllMyBuckets call. The script will print out the access and secret keys used for the deployment.

Mounting S3

The credentials for s3fs are placed into ~/.passwd-s3fs. We then try to mount the bucket using:

s3fs mybucket /home/user/s3w3 -o use_rrs=1 -o default_acl=public-read

The website will be stored on a reduced redundancy storage (RSS) and with the default access control that everybody can read the objects.

We have to unmount the S3 bucket before proceeding to the actual deployment: fusermount -u /home/user/s3w3.

Jekyll Deployment with S3

Now everything is in place and we can use the following git post-receive hook script to do the actual deployment to the S3 website bucket.

#!/bin/sh

set -e

GIT_REPO=$HOME/website.git
TMP_GIT_CLONE=$HOME/tmp/website
PUBLIC_WWW=$HOME/s3w3
S3_BUCKET=mybucket

# setup s3
s3fs $S3_BUCKET $PUBLIC_WWW -o use_rrs=1 -o default_acl=public-read

git clone $GIT_REPO $TMP_GIT_CLONE
jekyll --no-auto $TMP_GIT_CLONE $PUBLIC_WWW
rm -Rf $TMP_GIT_CLONE

# unmount s3
fusermount -u $PUBLIC_WWW

exit

Push and Test

We can test the script by pushing to the git repository and check the website at the S3 website endpoint. Have fun!