Add Amazon Cloudfront as CDN from S3 Storage

I have a small app that was serving file attachments directly from S3. Although I wasn’t doing any processing, it’s still preferred to deliver those over some type of CDN. Here I’ll lay out how I added an Amazon Cloudfront CDN so now my S3 assets are served from there instead of directly from S3.

I’m assuming you already have S3 setup to store your attachment files. This post will talk about the setup using the Paperclip gem, but you can use others like Shrine or Cloudinary.

So first you need to setup an Amazon Cloudfront distribution that will be linked to your S3 bucket.

Go to your Amazon AWS console and create a new Cloudfront distribution. There are loads of settings, and most of them I just left as the default. For the first one “Origin domain name”, click in the box and it will give you the list of all the S3 buckets in your account. Select the one you want. It will auto-fill the Origin-ID box. You can leave the Origin Path blank, or fill it in with a specific folder in your bucket that you want to use. For Protocol Policy, I switched it to redirect HTTP to HTTPS to ensure everything is using HTTPS. Everything else I left as the default. You can change them later. Your distribution is now created. It will take a few minutes to be deployed.

Note that your file needs to be set to public access.

To test it, go to your Amazon S3 bucket, and get the link to a file. It will look like s3.amazonaws.com/bucketname/path/to/filename.jpg. Open it in the browser. Now go to your cloudfront distribution, and replace “s3.amazonaws.com/bucketname/” with your cloudfront url, “xxxx.cloudfront.net”. You should be able to load the file in the browser from the cloudfront url.

What was not obvious to me is that when using the cloudfront url, you don’t need the bucket name. So for the S3 URL of

https://s3.amazonaws.com/bucketname/path/to/filename.jpg

the Cloudfront url is

https://xxxx.cloudfront.net/path/to/filename.jpg

No we can go to our Rails app and setup Paperclip to deliver the attachments from Cloudfront. In config/environments/production.rb

config.paperclip_defaults = {
:storage => :s3,
:url => ':s3_alias_url',
:s3_host_alias => "d30l9ueliue92c.cloudfront.net",
:path => '/:class/:attachment/:id_partition/:style/:filename',
:s3_credentials => {
:bucket => ENV['AWS_BUCKET'],
:access_key_id => ENV['AWS_ACCESS_KEY_ID'],
:secret_access_key => ENV['AWS_SECRET_ACCESS_KEY']
},
:s3_region => ENV['AWS_REGION'],
:endpoint => ENV['AWS_ENDPOINT'],
:s3_protocol => 'https',
}

With the key being the :s3_host_alias and :url and :path settings.

And you’re all set! You can also set up Cloudfront to deliver your actual Rails app assets (javascript and css), but I’ll do that in a later post.

credit here

Leave a comment