Rails 3 Asset Pipeline + Apache + Phusion Passenger - ruby-on-rails

I am using Rails 3.1 w/asset pipeline, phusion 3.0.x and apache 2.2.17.
In the configuration documentation at http://guides.rubyonrails.org/asset_pipeline.html, in section 4.1.1 it states that I need to add a section to my apache config:
<LocationMatch "^/assets/.*$">
# Some browsers still send conditional-GET requests if there's a
# Last-Modified header or an ETag header even if they haven't
# reached the expiry date sent in the Expires header.
Header unset Last-Modified
Header unset ETag
FileETag None
# RFC says only cache for 1 year
ExpiresActive On
ExpiresDefault "access plus 1 year"
</LocationMatch>
I have been assuming that Phusion Passenger has just been "handling" this... or have I been negligent in not RTFM? If I want to take advantage of the fingerprinting, do I need to add this to the apache config?

If you want the full benefits of the asset pipeline, you do, indeed, need to add this to your Apache configs. Without that section, your Apache configuration is likely specifically telling browsers not to cache assets - resulting in an unnecessary number of round trips between the browser and your server.
In order to get this to work, you may need to enable a few more Apache modules. To do this:
sudo a2enmod
# Choose headers
sudo a2enmod
# Choose expires
sudo service apache2 restart
To debug your set-up, I recommend using the Live Headers Firefox plugin. Using that, specifically request an asset URL (e.g. http://mysite.com/assets/application-8a0ae0b2d708f797674b7123c37501ba.css)and look at the cache headers before and after you make this change. Find an example asset URL by doing a View Source on any page.
After the change, you should see that the cache expiration is set to one year in the future.

Related

How to configure Phusion Passenger X-frame options?

I'm trying to iframe a site I built (using Rails) and deployed on an ubuntu instance on AWS using Phusion Passenger.
I looked more into it and found that I need to change my X-frame options, a HTTP header from 'SAME ORIGIN' to 'ALLOWALL'. I already added this line into my config/application.rb file and my config/environments/production.rb
config.action_dispatch.default_headers.merge!({'X-Frame-Options' => 'ALLOWALL'})
Even then, when I open my site, I still get these settings in my Network Headers:
Status:200 OK
Transfer-Encoding:chunked
X-Content-Type-Options:nosniff
X-Frame-Options:SAMEORIGIN
X-Powered-By:Phusion Passenger 5.0.11
This leads me to believe that there's a Phusion Passenger config file somewhere that I need to change the X-Frame-Options for. Any clues or help would be great, thanks!
X-Frame-Options header should be set in your vhost (usually Apache or Nginx). For security reasons, if possible, only allow HTTPS whitelisted domains and whitelisted paths.
<virtualHost *:443>
# ... Host and Passenger configuration ...
<Location "/your-iframable-path">
Header always set X-Frame-Options "ALLOW-FROM https://domain-using-iframe"
</Location>
</virtualHost>
I had the same problem. After trying for a long time, I found the solution to it.
Passenger uses a template for it's nginx configuration. When starting passenger, you pass the template to it using the --nginx-config-template parameter.
Now, to configure the X-Frame-Options header for passenger, simply edit the template file. Add the following line under the http { block of the template file:
add_header X-Frame-Options "SAMEORIGIN";
And make sure to run
sudo service passenger restart
To make the changes go live.
:)

Do I need use Gzip in a Rails 4 project?

I'm running some audits in my open-source project, BTC-Stores, and some times Chrome shows me that I need "Enable Gzip compression".
Sometime ago I read "High Performance Websites", from Steve Souders, and I already know the basic concepts about how make your page load faster. My project is using Ruby 2.0.0 and Rails 4.
I want know, Rails 4 already have a "gzip like compression" or I need to activate it by some gem or config? If you can, please link some good articles about Rails 4 performance and how to optimize it.
Here's some more about using gzip with Rails!
From http://guides.rubyonrails.org/asset_pipeline.html:
4.1.2 GZip Compression
When files are precompiled, Sprockets also creates a gzipped (.gz)
version of your assets. Web servers are typically configured to use a
moderate compression ratio as a compromise, but since precompilation
happens once, Sprockets uses the maximum compression ratio, thus
reducing the size of the data transfer to the minimum. On the other
hand, web servers can be configured to serve compressed content
directly from disk, rather than deflating non-compressed files
themselves.
Nginx is able to do this automatically enabling gzip_static:
location ~ ^/(assets)/ { root /path/to/public; gzip_static on; #
to serve pre-gzipped version expires max; add_header Cache-Control
public; } This directive is available if the core module that provides
this feature was compiled with the web server. Ubuntu packages, even
nginx-light have the module compiled. Otherwise, you may need to
perform a manual compilation:
./configure --with-http_gzip_static_module If you're compiling nginx
with Phusion Passenger you'll need to pass that option when prompted.
A robust configuration for Apache is possible but tricky; please
Google around. (Or help update this Guide if you have a good example
configuration for Apache.)
Also, the following may be of interest!
http://api.rubyonrails.org/classes/ActiveSupport/Gzip.html
Hope this helps!
Yes you need to use Gzip in a Rails 4 or any other project. You do that in the production server and not on your local.
Duplicated question: Compressing rails assets and nginx gzip (with nginx server)

Apache won't server static assets for rails app

I'm trying to configure my apache server for serving static assets from my rails app. I already tried the suggested configurations but my assets still aren't shown and when trying to access them directly I just got an rails error that no matching controller was found but the asset stuff should be handled by apache directly I think.
My apache configuration looks like this:
<VirtualHost *:80>
ServerName xxx
DocumentRoot /home/xxx/test/public
PassengerEnabled off
<LocationMatch "^/assets/.*$">
Header unset ETag
FileETag None
ExpiresActive On
ExpiresDefault "access plus 1 year"
</LocationMatch>
ProxyPass / http://127.0.0.1:9292/
ProxyPassReverse / http://127.0.0.1:9292/
</VirtualHost>
Did I missed something?
I used,
RAILS_ENV=production bundle exec rake assets:precompile
To make it all work right, I added this to config/application.rb...
module MyApp
class Application < Rails::Application
.
.
config.assets.precompile += ['custom.css']
config.assets.precompile += %w(*.png *.jpg *.jpeg *.gif)
.
.
end
end
(I had created custom.css.scss. But Rails did not recognize .scss, as you see above.) I assume that all your assets are appearing in public/assets folder after precompile. I don't understand what you are doing with LocationMatch, pardon my ignorance. Further more, I did not use port 80. I used 8000. Not sure if that makes a difference.
Also, there's a setting in config/environments/production.rb,
# Disable Rails's static asset server (Apache or nginx will already do this).
config.serve_static_assets = false
This is directly from the Rails Asset-pipeline documentation regarding the Apache server:
http://guides.rubyonrails.org/asset_pipeline.html
4.1.1 Far-future Expires Header
Precompiled assets exist on the file system and are served directly by your web server. They do not have far-future headers by default, so to get the benefit of fingerprinting you'll have to update your server configuration to add those headers.
For Apache:
# The Expires* directives requires the Apache module
# `mod_expires` to be enabled.
<Location /assets/>
# Use of ETag is discouraged when Last-Modified is present
Header unset ETag
FileETag None
# RFC says only cache for 1 year
ExpiresActive On
ExpiresDefault "access plus 1 year"
</Location>

Rails 3.2 Asset Pipeline with Thin and Apache, not finding assets

My question is similar to this one Rails 3.2 Asset Pipeline with Passenger Endless Errors except that when I try to actually go to
<link href="/assets/application-eed7996ee9017637f923133371ab3e92.css" media="all" rel="stylesheet" type="text/css" />
I get a 404. Here's the thing I don't understand. It is looking in /assets/, but when I look at the code that was deployed, the assets are only in /public/assets, which is actually a symlink to /var/www/myapp/shared/assets. So what in the world is responsible for telling the app that looking in /assets will produce correct results??
I am using Rails 3.2.0, ruby-1.9.3-p125, deploying to Ubuntu, Apache, and Thin.
I should clarify: My assets are indeed deployed to the server. Everything works perfectly fine until they need to be served, in which case production.log tells me it's looking for them in /assets/application-eed7996ee9017637f923133371ab3e92.css, which 404's.
For every request my thin.log says
cache: [GET /] miss
and production.log says
ActionController::RoutingError (No route matches [GET] "/assets/application-abecf2e096af9ee80697fd49e79a55e7.js"):
UPDATE
#Brandan thanks for the help. My assets are indeed in RAILS_ROOT/public/assets. I put this in my Apache vhost file:
DocumentRoot /var/rails/myappname/current/public
RewriteEngine On
XSendFile On
XSendFilePath /var/rails/myappname #not even sure if this line is needed
<LocationMatch "^/assets/.*$">
Header unset ETag
FileETag None
ExpiresActive On
ExpiresDefault "access plus 1 year"
</LocationMatch>
My RAILS_ROOT/config/environments/production.rb settings:
config.cache_classes = true
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
config.serve_static_assets = false
config.assets.compress = true
config.assets.compile = false
config.assets.digest = true
config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
Delete the following lines from your Apache configuration.
ProxyPass / balancer://thinservers/
ProxyPassReverse / balancer://thinservers/
The answer came from In Rails, should I enable serve_static_assets?.
Typically, your assets should only exist in /public/assets for a deployed application.
Apache should be configured so that its DocumentRoot is your RAILS_ROOT/public. Then it will serve http://example.com/assets/whatever.css from RAILS_ROOT/public/assets/whatever.css, and it never goes through Rails for static assets.
Have you restarted your application since you precompiled your assets? Sometimes Rails is expecting an older/newer compiled version of your assets than is currently deployed.
I've been having this problem for days now. Thought it was an issue with capistrano or the ruby version however I'm pretty sure it's permissions related too.
My configuration was pretty much the same as yours although I'm also using Unicorn.
Here's what I did to sort:
Temporarily remove the following section because I think that was causing problems with the troubleshooting:
<LocationMatch "^/assets/.*$">
Header unset ETag
FileETag None
ExpiresActive On
ExpiresDefault "access plus 1 year"
</LocationMatch>
Perhaps get it all working and then add it back in. I don't think it's the cause of the problems however, when diagnosing things like this, it's best to remove as much as you can to find the culprit.
Run a chown -R xxx.xxx (replace xxx with your application user or web user) on the public directory. As soon as I did so, the css appeared again.
(What I did but maybe not essential) You might also want to install locally without cap. just in case there's an issue with it. That also worked for me.
Completely wipeout tmp/cache and public/* just in case.
Restart your apache server a couple of times.
You can see a gist of my conf. here
Try removing the ProxyPass and ProxyPassReverse directives from your apache/thin configuration. The P flag in your rewrite rule is already performing the proxy pass that you desire.
See http://httpd.apache.org/docs/2.0/mod/mod_proxy.html for more information.
Passanger knows its a RoR application as there is a config.ru file.
The same error you are reporting happened to me due to wrong permissions. Apache was not able to serve the files inside assets, but was able to send the files on public/
In my case I use capistrano so assets was a symlink to shared/public/assets.
what I did was:
chmod -R o+x shared/
x permissions are required to list and access directories. After that it worked. You have to make sure that assets has +x for others

Compressing a JSON response from a Rails app

We have an app that queries for locations for a customer. We're getting to the point where some customers could have upwards of 10,000 locations. The JSON response for this can get quite large, over 1mb sometimes.
I'm wondering first off the best way to compress this. We have apache in front of a Rails app running in trinidad with JRuby. Can I just set mod_deflate to always compress any responses that are application/json? How might I go about doing this?
Next, what is the browser support for gzip'd json? When I gzip a sample response of 200k it goes down to 30k. That's a significant savings. We're really like to be able to minimize the size of that response without having to minimize the number of locations returned.
In general, for newer versions of Rails, you can do it by adding
use Rack::Deflater
before the "run" line in the config.ru file. This will work perfectly with browsers/clients that support gzip. We use it in production on major websites.
Note for JRuby users: This assumes that your Rails app is launched through Rack, which it often isn't for JRuby. You need a recent version of JRuby-Rack and configure it in Warbler to run in 'rack' mode instead of 'rails' mode.
If the browser supports gzip'd/deflated data, then JSON will go through it just fine. AJAX data is just a regular HTTP request that was done on behalf of a script, rather than a human. At the HTTP level, there's absolutely zero difference between transferring some HTML or a JSON string - it's just data.
For Googlers... [I'm running Apache 2.2.16 and don't care about IE6]
JSON Responses with Content-Encoding = gzip didn't happen until I edit mod_deflate.conf to include this:
AddOutputFilterByType DEFLATE application/json
You can check server response headers with Firefox / Firebug / Net tab
First, make sure you have apache's mod_deflate installed by running this command.
a2enmod deflate
If this command installed it, restart apache. If not, you're good for now.
service apache2 restart
In apache2.conf usually located at /etc/apache2 append this line to the end of the file. This will include a file that we'll create in a little.
Include mod_deflate.conf
Next, we'll edit the mod_deflate.conf with our options:
SetOutputFilter DEFLATE
SetEnvIfNoCase Request_URI \
\.(?:exe|t?gz|zip|bz2|sit|rar)$ \
no-gzip dont-vary
SetEnvIfNoCase Request_URI \.pdf$ no-gzip dont-vary
#Skip browsers with known problems
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
The first block of code disables gzipping exes, gzs, pdfs.. etc
The second block of code skips deflation from browsers that don't support it.
Finally, restart apache again
service apache2 restart
The settings were copied from the link below:
http://www.howtoforge.com/apache2_mod_deflate

Resources