Heroku + Rails4.2 : Cloudfront setup - ruby-on-rails

I am trying to setup Cloudfront for my heroku app. The documentation seems to be lacking to stand independently.
Here are the steps I followed:
1. Setup Cloudfront in AWS console
2. Added cloudfront domain name to production.rb `config.action_controller.asset_host = 'XXXX.cloudfront.net'`
3. Set `config.assets.compile = true` in production.rb
4. Verified AWS_SECRET_ACCESS_KEY is correct in heroku config
5. I have added `gem 'rails_12factor', group: :production`
None of assets load anymore. Any step I am missing in the setup?
Update1:
In the chrome debugger the asset is correctly requested from cloudfront from this url: http://XXXXX.cloudfront.net/assets/application-22c7c249df1a24541d86603b0715eefe.css
However in the request header see a Status Code:302 Moved Temporarily. I am wondering if I have a redirect loop and how I can debug it.
Update2
Thanks everyone for the suggestions. Some more info:
When I try to download the asset from my app, I get a redirect to home page on browser but using curl I am able to get the asset. ex: curl 'http: //www.myapp.com/assets/application-c9a778bb55ad4152d956fd34fe6f7839.css'
The app doesnt use SSL. However I have still set Origin Protocol Policy to Match Viewer as per #Omar's suggestions
I tried to download the asset from my app on browser and am able to access the assets. ex: 'http: //www.myapp.com/assets/application-c9a778bb55ad4152d956fd34fe6f7839.css'
However trying to access the assets directly on cloudfront (d1ax5oefcdtdki.cloudfront.net/assets/application-c9a778bb55ad4152d956fd34fe6f7839.css) redirects it to myapp.com
Screenshots for cloudfront DS:
https://www.dropbox.com/s/bkg480d4it6zl2r/Screenshot%202015-12-06%2014.01.28.png?dl=0
http://glui.me/?i=7ah73hffrhvmpt7/2015-12-06_at_2.02_PM.png/
https://www.dropbox.com/s/dd4wwgm3md8w7qn/Screenshot%202015-12-06%2014.05.20.png?dl=0

For anyone else having issues debugging cloudfront.
The problem was Cloudfront had cached redirects (prob bec of wrong setup). After invalidating the cache I was able to force CF to fetch assets from my app and serve them.

When you request the asset for the first time, cloudfront checks whether the file is cached or not so for example you request:
http://XXXXX.cloudfront.net/assets/application-22c7c249df1a24541d86603b0715eefe.css
for the first time cloudfront will give a cache miss and then it will pull the file from it equivalent path from rails. So that the next time you request the same file, it will be already cached.
In order for this to work you need to make sure that you have everything setup correctly.
From rails side there is nothing much to do except setting the assets_host in production.rb. As you already have the rails_12factor gem there is no need to add the config.assets.compile = true. From the documentation of the gem you can see in the how section that it add serving static assets "the documentation".
From cloudfronts side that is where I think you are facing a problem, you need to set some settings to let cloudfront know how it can communicate with your rails app when the cache misses. In the cloudfront setting you need to check the
Origin Domain Name to be the url of your rails app.
Origin Protocol Policy to Match Viewer
Distribution State to Enabled
Also there are some other settings there that can help you optimize your content delivery caching.

Related

Rerouting to AWS hosted assets from a Heroku Rails app

I have a Heroku hosted Rails app that has reached the 300MB limit for the slug size and can no push to Heroku. To fix this issue, I've setup an AWS S3 account and want to redirect the assets being requested from my Rails app to the new S3 location. The Rails app is basically just serving JSON files that point to the static assets using a relative URL. An iOS app using the Rails JSON then has a hardcoded domain URL, and appends the path to the resources to that domain and requests assets it needs.
I want to update my Heroku app and change my asset locations without requiring an update to the iOS app in order to change the asset domain. So, I need to redirect static asset requests from the Rails app to the AWS server.
In my git repo, I've ignored the assets in the public folder that I've moved to the AWS server. The asset files are present on my local machine, but are not part of the git repo when uploaded to Heroku.
So far I've tried changing the config.action_controller.asset_host which does not seem to work since these are static assets and are being returned by the web server before Rails gets it.
I tried using routes rules to redirect to a different domain, but these routes never seem to be captured. The static files appear to be returned before the Rails app has a chance to handle the request.
I've tried using the rack-rewrite gem to try and redirect my assets to a different domain with the following in `initializers/rack_rewrite.rb:
require 'rack/rewrite'
AppNamespace::Application.config.middleware.insert_before(Rack::Lock, Rack::Rewrite) do
r301 %r{/images(.*)}, 'http://my-subdomain.amazonaws.com/images$1'
end
This doesn't seem to work either and it always just returns the static files.
So far I've been trying for hours to figure out the proper way to handle this situation. I'm not a Rails developer by trade, I build iOS apps, so please let me know if I'm going about this the wrong way or completely missed the "right" way of doing this.
I solved this using routes and the 'rails_serve_static_assets'. I had to move the local images out of the public folder in order to avoid Nginx from returning the images before hitting the Rails app. The route ended up like so:
match '/images/(*path)', :to => redirect { |params, request|
"#{Rails.configuration.assets.aws_url}#{request.path}"
}

Setting Asset Cache Expiration in Rails / Cloudfront / Heroku

I'm getting errors from the Google pagespeed tool saying that cache expiration is not specified for my assets.
I'm serving asserts through cloudfront, and my site (Ruby on Rails) is hosted on Heroku
https://www.driverhunt.com/…9a42dc64767309bbb76af8a1eaef10b3c0cb.css (expiration not specified)
https://www.driverhunt.com/…74901ff9e954e9fca26f71542e8fc8d807684.js (expiration not specified)
https://www.driverhunt.com/…ad7b9e065ed95559bdf1c426bc94834f09e0.jpg (expiration not specified)
Firstly, it looks like things AREN'T being served by cloudfront. Second:
Is this a cloudfront issue, a heroku issue, or a rails issue? Can it be solved programatically, or do I need to fiddle with the heroku/cloudfront settings?
Set the response header
To enable browser caching you must set the Cache-Control and the Expires response header.
Debugging tip
To see your existing cache settings, use your browser's debugger. For Chrome, while on any page in your app, open the debugger and look under:
It's important to see what effect your code changes make. Run this on your app as is and get a baseline Response header.
Setting the response headers
When you have access to the server config files setting caching on Linux running Apache or Nginx is simple. But it's my experience that Heroku does not permit you to modify server config files directly.
Without the capability to modify .htaccess or nginx.conf on the server you have 2 options:
1- Implement caching for your rails app at the controller level, e.g.:
def show
#company = Company.find(params[:id])
expires_in 3.minutes, :public => true
# ...
end
Which is an admittedly hideous solution.
2- The other option Heroku offers is HTTP caching using Rack::Cache (Memcachier Heroku add-on). I have no experience with this, so no comment.
Conclusion
Heroku provides a wonderful and simple deploy environment, but to offer that simplicity, they have locked down configuration. I used Heroku to develop and deploy an app in test mode, but moved to a VPS where I could implement server side optimizations, such as caching to launch the app.
P.S. To address the CDN part of the question: Since it is your sever setting the response headers, I don't think the CDN config impacts caching.
Your assets are being served through your rails app. The relevant setting is config.action_controller.asset_host which should be set to point to your cloudfront distribution, for example
config.action_controller.asset_host = '//d123467890.cloudfront.net'
This assumes that your cloudfront distribution is already configured to serve your assets (for example from a bucket populated by asset_sync)

How do I get my rails assets to be served by cloudflare instead of my server?

I'm running a rails app on heroku and recently switched to cloudflare for CDN for asset serving. My understanding was that once I use cloudflare, my assets (ie js,css,images) would be served from cloudflare and not from my own server but in my heroku logs I still see the requests for assets. Do I need to configure something in my rails app like setting the asset_host or something? Thanks.
It might be helpful to clarify what CloudFlare caches by default as well (just to make sure you know that not every file extension is automatically cached).
Note: Caching also depends on how many requests we get for the resources before it gets cached (minimum of three).

Problems serving .js and .css assets cloudfront CDN Heroku Rails 4 App

I am trying to host the assets of my Rails 4 App over Cloudfront CDN. I used to use asset_sync and s3 but I wanted to switch over to a CDN.
When I go to my Heroku App, I see that all the pages are just bare HTML. None of the JS or CSS is being loaded.
These are the errors I am getting from my Console:
Screenshot of console errors: http://i61.tinypic.com/15rxdsj.jpg
Also, I am not sure if I have set up my Origin Domain Name and Origin Path correctly on the Cloudfront Origin Settings.
Currently I am using my heroku app url as the Origin Domain Name and "/production/assets" as the Origin Path.
Production.rb file: http://pastebin.com/2dzLpGfE
I have been trying unsuccessfully for the past week to get the Heroku app to display the CSS and JS. I would greatly appreciate any insight. Thanks in advance!
Moving to Cloudfront isn't as drastic as change as you seem to think if you had everything working from S3. After all, Cloudfront simply distributes the contents of your S3 bucket to edge locations. This means you just have to let Rails know to look for the CDN and not S3.
There are a lot of things that could be going on. You could have misconfigured Cloudfront, which should be pointing to your S3 bucket as the origin. You should test that setup by checking to see an asset in the browser by using the Cloudfront URL. The main point is that Cloudfront should have no idea about your Rails app.
Meanwhile, you can still use AssetSync to push your assets to S3 "underneath" an assets path. You must also configure config.action_controller.asset_host as described here.

When the protocol is https, Amazon S3 assets won't load, - Rails, Heroku

I set up asset_sync gem on heroku, following this URL: https://github.com/rumblelabs/asset_sync
The settings are working and I uploaded all the static assets at S3.
The problem is, when I open page through https protocol, can't access any of the assets, because the browser returns "This Connection is Untrusted". (same with Chrome & Firefox).
Every assets will be able to use after I admit access to s3 assets url. https://myapp.asset.s3.amazonaws.com/assets
Anyone had same problem? how to fix this problem?
The SSL certificate for s3 is a wildcard certificate, i.e. it is for *.s3.amazonaws.com. However a lot of certificate checking libraries define this to cover foo.s3.amazonaws.com but not foo.bar.amazonaws.com: wildcard certificates only go one level down.
The simplest solution is to pick a bucket name with no dots in it, e.g. myapp-assets.
Another solution is to access the files as https://s3.amazonaws.com/myapp.asset/assets/.... I believe you'd have to set config.assets.prefix to tell rails that the assets aren't in the normal location relative to the asset host.

Resources