I am using DigitalOcean Spaces to store images uploaded via ActionText/ActiveStorage. This works great. I have now created a CDN (via DigitalOcean) which I’d like to put in front of my images.
My goal is for links in my ActionText to use the CDN (e.g. https://cdn.myapp.com/image-goes-here.png) rather than /rails/representations/etc links which hit my app, but I’m finding it rather unclear whether this is possible. I found this comment buried on a Rails pull request:
However, what this appears to do is replace the host name in the URLs but not the path (/rails/representations is still in the path which doesn’t work for my CDN). I could take this and hack it to remove the Rails-specific paths but this feels really dirty and wrong.
Has anyone managed to do this before and is it even possible? I’d love some advice. It feels like something that should be baked into Rails at some point.
Thanks for the replies, all of which I think will work with standard ActionStorage images. However, these solutions won’t work for images attached to ActionText RichText objects as far as I can tell. As @sdubois mentions, it’s unclear how to make a CDN work with ActionText.
@sdubois believe you need to set up access policy for the S3 bucket to allow connections from CloudFront, this is pretty straightforward in aws console (they even give you a copy-paste option). This way your S3 bucket stays private but CloudFront can connect to it.
However, it should not matter these days as the way to set it up recommended by Rails guides is to use proxy mode and set your CloudFront origin as the app domain. This way, first time the asset is served by the Rails app, which will download it from S3, serve to CloudFront at /rails/active_storage/blobs/proxy/xxx and let CF cache it.
Thank you @Janusz_M for taking the time to explain! So it should be possible to have CloudFront cache the assets, but to still ensure that CloudFront URLs at which the files are served are short-lived using CloudFront signed URLs? This would be to ensure that the generated URL provided in the source code of the website’s HTML response is only valid for, say, 5 minutes, and then won’t work any more. Then to get the file again a new authenticated request needs to be performed again (but the data would then be re-downloaded from CloudFront’s edge, to maintain performance).
I really appreciate your posts, and it helped me a lot.
I still have two questions:
You mentioned image_tag(ENV['CDN']) + talent.avatar.key; well it works well, but this is permanent. If anyone gets access to the key, they can access the image from everywhere, anytime.
If I use what has been provided in Rails 6, for rails_storage_proxy_url what should be passed as host here? It can’t be the same as ENV['CDN'] because that directly points to the CDN server. Shouldn’t it be the host that points to the Rails app?
So, all in all, what I see as the benefit of using cdn_proxy_url is: it won’t disclose the key to the end user. Instead, an end user will see a Rails URL, something like: /rails/active_storage/blobs/proxy/.