====================
== Skoot and Doot ==
====================
A site to talk about whatever I want.

Using R2 as an image CDN for my Hugo blog

default

Overview

This blog is built using Hugo, and uses R2 as a CDN to serve images. R2 offers up to 10GB of free storage, and serving images from a CDN keeps the repo small and build times short.

I found this blog post1 that gives a great explanation of how to do this. It’s over a year old now, so YMMV. The following are some notes/modifications that I made in my own setup. I recommend starting with that blog post, and then reading below if you’re interested.

My custom img shortcode

The blog above suggests an example shortcode that will render HTML image tags that fetch the images from the CDN. This is great, but for local development I prefer to serve images from my local machine. To handle this, I wrote my own shortcode that serves images locally in development mode, and only fetches from the CDN when built for production. You can see that shortcode and instructions for installing it in the public repo2.

Compressing images

Images should be compressed for web before uploading to the CDN host. You can do this on Linux easily (for JPGs) with the imagemagick or graphicsmagick. I found a Stack Overflow post that had some suggestions3, and then made a small modification. This is what I run before uploading photos:

# https://stackoverflow.com/questions/7261855/recommendation-for-compressing-jpg-files-with-imagemagick
# - Quality 85
# - No blur
# - strip EXIF data
#
# This stackoverflow post actually recommends using Gaussian blur. However, I
# noticed a significant degradation in the image quality when using blur. The
# below configuration achieves a similar compressed file size by reducing the
# "chroma channel resolution" with -sampling-factor 4:2:0 and using a more
# accurate "floating point discrete cosine transform" with "-define
# jpeg:dct-method=float".
magick <input_file> \
  -strip \
  -interlace Plane \
  -sampling-factor 4:2:0 \
  -define jpeg:dct-method=float \
  -quality 85% \
  <output_file>

Smashing Magazine also has a great article3 that goes into detail about resizing images for the web.

Syncing the local image folder

The blog post1 recommends using Cyberduck to upload photos. This is fine, but I prefer something on the command line so I can more easily build scripts. I went with rclone, which is easy to setup and includes good examples in their documentation4. See the docs for configuration instructions.

To upload my images, I just push my local static/images folder to the R2 bucket with:

rclone -v copy static/images/ r2:skootanddoot/static/images

Demo

Here’s an image! In my Hugo content markdown, the shortcode tag looks like this:

<img src="/images/posts/image-hosting/tea-fields.jpg" caption="Beautiful rolling tea fields on our recent trip to Alishan">
Beautiful rolling tea fields on our recent trip to Alishan

Beautiful rolling tea fields on our recent trip to Alishan

The CDN URL is automatically prepended to the filepath, to create an image tag that looks like this:

<img src="/images/posts/image-hosting/tea-fields.jpg" alt="Beautiful rolling tea fields on our recent trip to Alishan">