Changelog: Images from a CDN

Shrinking deployment size 97% by serving images from CloudFront.

Image variants are now served from a CDN at img.alexleighton.com instead of being bundled into the site and served by Amplify.

It seems I never came back to detail the custom image system underlying the images on this static site, so let's begin with the before, to motivate the after. The image system comprises a private S3 bucket, local filesystem cache, image "database", and an image system library.

The image system library is written in OCaml and integrated into the static site generator, to allow image reference resolution. A separate executable fronts the image system, to allow uploading and syncing of images during post authoring. Image upload through the system generates a number of variants of different sizes and formats (jpeg as the lowest common denominator, webp for most browsers, avif for modern browsers), assigns a TypeId to each image, uploads the images to the source-of-truth private S3 bucket, adds them to the filesystem cache, and adds corresponding rows to the CSV image database. The site generator reads the image database to dereference image TypeIds into source URLs, copies every referenced image into the output directory, and includes those images in the release artifact.

Deployment of the site looks like executing a script to build and execute the site generator, packaging up all the artifacts into a single zip file, uploading that file to the website S3 bucket, and triggering an Amplify deployment on it. It is this zip file that initially motivated me to serve images from a CDN. Upon introduction of the image system, my zip files began ballooning to 20MB, and up to 68MB when holding the site's ~525 images.

Each upload contained the same duplicated images, pushing the total size of stored data over 1GB. At first I implemented an S3 lifecycle rule that prunes unmarked zip files older than 90 days (I mark the first zip file of each month, plus any particularly important releases, as backups), and this kept the size somewhat in check. But the zip's size kept going up and I didn't like the time it took to upload the ever-larger file to S3, so I decided to change the deployment of images.

After the change, the system now uploads new images to a "public" S3 bucket, which CloudFront serves on img.alexleighton.com. Local site generation uses images from the cache so I don't need the internet to write posts, but site generation for distribution no longer includes any images, resulting in the site's zip file dropping to 1.8MB. Looking forward to marginally faster deployments and to saving a couple of pennies in bandwidth and storage costs per month 😆.