Storing assets in an AWS bucket
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: yo.katydecorah.com
and *.katydecorah.com
.
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:
- type:
CNAME
- host name:
yo
- target name:
1234abcd.cloudfront.net
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
Disallow:
User-agent: *
Disallow: /
Generate photo versions
For each photo, I created these versions based on the max-width of my site:
- 1600px wide
- 1600px wide in webp
- 1000px wide
- 1000px wide in webp
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:
- Find:
<img([\w\W]+?)>
- Replace:
{% include img.html $1 %}
For markdown images:
- Find:
(!\[(.*?)\]\()(.+?)(\))
- Replace:
{% include img.html src='$3' alt='$2' class='' %}
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.