A new way to deploy to Amazon S3

Pretty much since I began hosting this site on Amazon S3 I've been using middleman-s3_sync to do the heavy lifting of syncing files to the bucket. Unfortunately, somewhere along the way it stopped picking up certain files that should've been synced. I tried to be a good OSS citizen and find a fix, but after delving into the Middleman innards, I couldn't find the problem.

A new method

A new method of deploying the site was needed and recently I moved to using Amazon's own aws cli utility. After years of providing next to nothing in regards to tooling, Amazon have released their own command line utility for interacting with AWS. And the best part is that it seems very nice .

This is how I now deploy the site.

1
2
3
4
5
aws s3 sync build s3://jordanelver.co.uk \
  --profile jordanelver.co.uk \
  --delete \
  --acl public-read \
  --exclude *.DS_Store \

build is the local directory to be synced, and s3://jordanelver.co.uk is the remote S3 bucket.

--delete says to delete files at the destination that are not in the build/ directory.

--profile controls which credentials and other settings to use when connecting to S3. More on this below.

--acl public-read makes the synced files publicly readable, as required by S3 static website hosting.

--exclude excludes those pesky .DS_Store files that OS X litters around the filesystem.

Credentials

Credentials are stored in ~/.aws/credentials. I have a section like this.

1
2
3
[jordanelver.co.uk]
aws_access_key_id = <ACCESSKEY>
aws_secret_access_key = <SECRET>

You'll see that this matches the --profile jordanelver.co.uk line in the s3 sync commandline.

That covers authentication, but you can also specify additional configuration values in ~/.aws/config. In this case, the S3 bucket region.

1
2
[profile jordanelver.co.uk]
region = eu-west-1

I used aws configure --profile jordanelver.co.uk to configure these values.

One last thing

One last thing that deserves to be mentioned is the --dryrun flag. It's very handy for testing what's going to happen, before it happens. I ended up wrapping my sync command in a Ruby script to conditionally add --dryrun as and when I need it.

Happy syncing!