Invalidate distributions and files on Cloudfront for Middleman websites

I've been deploying and pushing a lot to my personal website as of late. It's built using Middleman, a static website generator with a bunch of handy shortcuts and tools. As far as hosting goes, I have the entire build sitting in an AWS S3 bucket. I wrote a short article detailing how I host the website using HTTPS, S3 and help from Cloudfront.

Lately though, it's been a pain in the ass. Because of the Cloudfront distribution, all my files are cached. Which means that I have to go into Cloudfront manually, create an invalidation for my HTML and CSS files so that my website displays the updated content.

I was sure someone had run into this problem in the Middleman realm before. And if not, I would have built a Gem myself. But luckily for me, Leigh McCulloch (@leigh) already built a sweet little deploy tool called Middleman CDN. Thank you Leigh!

The build tool is very straight forward. Instructions can be found in the repository here: https://github.com/leighmcculloch/middleman-cdn

I thought it'd be good to give a rundown of the steps I took to get middleman-cdn working for my website:

  • Here's what my gemfile looks like - very simple:
      
        gem 'mime-types'
        gem 'middleman', '4.2.1'
        gem 'middleman-livereload'
        gem 'middleman-s3_sync'
        gem 'middleman-blog', '~> 4.0'
        gem 'middleman-cdn'
      
    

    middleman-livereload reloads my website in local development upon save of an edited file. middleman-s3_sync is for syncing my files with my AWS S3 bucket. middleman-blog is for building out the blog portion of my website which your on right now reading this article. middleman-cdn of course allows us to invalidate our Cloudfront distribution.

  • Once I added middleman-cdn to the Gemfile, bundle install

  • Following up on the instructions for middleman-cdn, I adjusted my config.rb file in the root of the Middleman project.

      
        activate :s3_sync do |s3_sync|
          s3_sync.bucket                     = "www.lukeduncan.me"
          s3_sync.region                     = "us-east-1"
          s3_sync.aws_access_key_id          = "xxxxxxx"
          s3_sync.aws_secret_access_key      = "xxxxxxx"
        end
    
        activate :cdn do |cdn|
          cdn.cloudfront = {
            access_key_id: 'xxxxx',
            secret_access_key: 'xxxxxx',
            distribution_id: 'xxxxxx'
          }
          cdn.filter            = /\.html$/i
          cdn.after_build       = false
        end
      
    

    The "xxxxxx" are my actual keys and ID's that I am unwilling to share with you at this time for obvious reasons lol. For the most part, I use a CSS framework and don't really write any custom CSS so I just worry about invalidating the HTML. If I do need to write specific CSS, I usually just write it inline - sue me!

  • Once got this setup, I run through my typical build process:

      
        git commit -am "New commit"
        bundle exec middleman build
        bundle exec middleman s3_sync
        bundle exec middleman cdn
      
    

    I did see middleman-cdn Gem itself has documentation around hooking into the s3_sync command. Technically this would automatically generate the invalidation based upon the updated files for pushing to S3. But unfortunately Middleman 4.0+ got rid of hooks (I think???) so it can't be used anymore. But I have an alias through my ZSH config, that runs all these commands in one.



And boom goes the dynamite. An updated Middleman website hosted on S3, CDN'ed through Cloudfront and invalidated when needed.