Storing assets in an AWS bucket

code • November 4, 2018

This is part II to Download Flickr photos in your Jekyll posts and a rundown of how I setup a subdomain that points at an AWS S3 bucket to host my site’s assets. And https, too!

Create a bucket

I started by creating a bucket on S3 to store my photos. To keep my bucket secure and allow me to test locally, I added a policy to allow my IP address access. In the next step, I’ll allow CloudFront to configure my bucket policies further.

Make it https

Next, I followed these instructions to serve HTTPS requests for my Amazon S3 bucket.

💡 When creating your SSL Certificate, under the Add domain names section, also add an * version of your domain. For example: and *

I also pointed my subdomain at CloudFront bu copying the value of Domain Name from my distribution. Then from my domain host, I created a CNAME record that points at that CloudFront domain name. For example:

Secure assets to the domain

To keep my assets secure, I followed the steps on How to Prevent Hotlinking by Using AWS WAF, Amazon CloudFront, and Referer Checking (I used Approach 1: A separate subdomain).

Next, I followed these steps to allow access to an Amazon S3 bucket only from a CloudFront distribution.

Now only my site can load my content, which keeps others from hotlinking my stuff and driving up my AWS bill.

Create a custom error page

Now that CloudFront is blocking traffic to my bucket outside of my domain, I created an error page. I did this in CloudFront by clicking Error Pages and then Create Custom Error Response. From the dropdown I selected 403: Forbidden and hit Yes on Customize Error Response. I entered a response path of /oops.html which is a file I uploaded to my bucket.

Create robots.txt

You’ll likely want to create a robots.txt file in your root directory to keep engines from indexing your assets. You can enter the following in your robots.txt file:

User-agent: *
Disallow: /

If you use images in your social media meta tags, then you’ll want to allow certain crawlers such as Twitterbot:

User-agent: Twitterbot

User-agent: *
Disallow: /

Generate photo versions

For each photo, I created these versions based on the max-width of my site:

For the time being, I’m using Panic’s Transmit to sync my photos to my bucket. I’m now working on a build script that will resize images and upload it to S3 for me (stay tuned 📺).

Replace img with picture

As a last step, I replaced all instances of the img element with picture so I could use srcset.

To put in place, I decided to create an include called img.html. I used my code editor’s regex find and replace to swap out the img element for the new include in all my posts:

For markdown images:

Both regex searches keep all attributes intact, which means that I’m passing the original image’s src, alt, class attributes as variables to the include.

The include has logic and the picture element. The include determines which size photo to display based on the classes that are passed through to the include. When I’m developing locally, my site will use my AWS bucket’s URL that my IP address can access (set by permissions when I created my bucket earlier).

You can check out the include on GitHub.

We’ll see

I’m not sure how this new journey of hosting my assets on AWS will go, how my include will change, or the future of my photo sizes. Still, it was really fun figuring out all the pieces.

Keep reading code