Nginx Rails/Passenger is not serving gzipped asset files - ruby-on-rails

Nginx 1.10.1 Rails 5.0.1. The asset pipeline is making both the zipped and native versions of the css and js files, but only the uncompressed is served to the browser. I can see both versions in public/assets and I can use curl to retrieve the zipped version by appending '.gz' to the css/js asset url delivered to me.
I am using a CDN (AWS CloudFront) but have tested without the CDN and anyway it should still point me to the zipped version, right?
nginx has --with-http_gzip_static_module. Using this answer as a guide, my nginx config (edited) has:
http {
server {
listen 80;
server_name idoimaging.com www.idoimaging.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name idoimaging.com www.idoimaging.com;
root /var/www/idoimaging/current/public;
location ~ ^/(assets)/ {
gzip_static on;
}
}
}
I've also tried /assets/ as the regex in location. In my production.rb:
# Have also tried setting this to false
config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
config.middleware.insert_before(Rack::Sendfile, Rack::Deflater)
config.assets.compress = true
config.assets.js_compressor = Uglifier.new(mangle: false)
I'm testing with Chrome with cache disabled, also for speed with curl https://idoimaging.com | grep assets which I believe should have the same behaviour as the browser?
I don't know why nginx will not serve the gzip'ed js/css asset files when they are present.
EDIT: I've also seen this guide that takes another approach: Use Rails as the static asset server instead of nginx. Would this be a better approach?

Given that Rails is producing the gzipped assets, we can be confident that the issue resides solely with nginx. So let's focus there!
I believe Nginx is faster at serving static assets than Rails is, so I'd stay away from using it as a static asset server in any event.
Now looking at the URL you provided (https://idoimaging.com), your server appears to be providing gzipped files. So the issue is just with your testing approach (assuming this is the correct URL, and you have not changed the server configuration since this post).
Your curl command doesn't include the Accept-Encoding: gzip header, which tells the server your client is capable of handling gzipped files. Without it, Nginx will serve the uncompressed versions. You can see the difference in commands and outputs in this gist. The difference is in the Content-Length and Content-Encoding response headers.
If you're seeing something different, let me know!
Edit 1
That's odd, CloudFront appears to have cached redirects for both your CSS and your JS.
richardseviora:Richards-MacBook-Pro#~> curl "https://cdn.idoimaging.com/assets/application-0cd41e63d35c1e5a7ab76ded23fbaf2ef1d1b786144134a80a1dfa9c765cff0d.css" -I -H "accept-encoding: gzip"
HTTP/1.1 301 Moved Permanently
Content-Type: text/html
Content-Length: 185
Connection: keep-alive
Server: nginx/1.10.1
Date: Thu, 23 Feb 2017 03:30:49 GMT
Location: https://idoimaging.com/assets/application-0cd41e63d35c1e5a7ab76ded23fbaf2ef1d1b786144134a80a1dfa9c765cff0d.css
Age: 942
X-Cache: Hit from cloudfront
Via: 1.1 d8b73f8fefd106d5c95f11977e132c46.cloudfront.net (CloudFront)
X-Amz-Cf-Id: ao8PwibmSj1JhmfbmuNfC2gYi9x-RTcCrJDAqLWAUIyOjP_3qYTGQA==
# It should look like this instead.
richardseviora:Richards-MacBook-Pro#~> curl -I -H "accept-encoding: gzip" "http://cdn.sweatrecord.com/assets/application-b932da0ddcf53d3650da5135b083224e863b349c784f3d1e3ca992b36ce3e31d.css"
HTTP/1.1 200 OK
Content-Type: text/css
Connection: keep-alive
Accept-Ranges: bytes
Content-Encoding: gzip
Date: Thu, 23 Feb 2017 03:50:13 GMT
Last-Modified: Mon, 30 Jan 2017 16:29:44 GMT
Server: Apache
Vary: Accept-Encoding,Origin
X-Cache: Miss from cloudfront
Via: 1.1 8b5947aba7280333032d4dcdd80b3489.cloudfront.net (CloudFront)
X-Amz-Cf-Id: FN9FyKl0RCpNTTqBwb0WyQhbDd-rEyyQ05eCtaFCD8YaH_FtjG7Q8Q==
This is Nginx issue, but I'm not sure where exactly because CloudFront will cache 301s.

Related

Rails + Passenger on Heroku: How to set expiry date or a maximum age in the HTTP headers for static resources?

I'm using Rails api with an angularjs front-end which is served simply as static files under public directory. I've chosen passenger as the app server, deployed to heroku and everything seems to be working fine except for caching.
Since static assets are served by passenger/nginx, I believe this has nothing to do with rails. But I have no idea how to get it working or where to add configurations.
Response headers when requesting a static file (application-a24e9c3607.js):
Connection: keep-alive
Content-Length: 0
Date: Thu, 14 Jan 2016 06:45:31 GMT
Etag: "5696ce02-43102"
Last-Modified: Wed, 13 Jan 2016 22:21:54 GMT
Server: nginx/1.8.0
Via: 1.1 vegur
I was able to solve it like this:
create nginx.conf.erb file:
cp $(passenger-config about resourcesdir)/templates/standalone/config.erb nginx.conf.erb
Inside server block in nginx.conf.erb, instruct Nginx to generate appropriate headers when a file under our assets directory is requested:
server {
# ....
location ~* ^/assets/ {
# Per RFC2616 - 1 year maximum expiry
expires 1y;
add_header Cache-Control public;
# 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.
add_header Last-Modified "";
add_header ETag "";
break;
}
}
Pass Nginx engine options to passenger in Procfile:
web: bundle exec passenger start -p $PORT --max-pool-size 3 --nginx-config-template nginx.conf.erb

Rails 4 + Nginx - serve font via CloudFront won't load cause by CORS

I've website at http://revoniaga.com which is run RoR but the font won't load where it said "blocked from loading by Cross-Origin Resource Sharing policy". It cause by Amazon CloudFront. I've try everything but still same result.
First, I put my font assets under /app/assets/font
then in my css (vendor/assets/stylesheets/font-awesome.css), I use something like this:
#font-face {
font-family: 'FontAwesome';
src: url('/assets/fontawesome-webfont.eot?v=4.3.0');
//and so on for other font format
}
At my /etc/nginx/sites-available/revoniaga_production, I put
location ~* \.(eot|otf|svg|ttf|woff|woff2)$ {
add_header Access-Control-Allow-Origin *;
}
Then when I curl:
curl -I https://d3bkb7gt2ds4m6.cloudfront.net/assets/fontawesome-webfont.woff2
It said
HTTP/1.1 404 Not Found
Content-Type: text/html
Content-Length: 168
Connection: keep-alive
Server: nginx/1.6.2
Date: Wed, 18 Mar 2015 09:34:29 GMT
Age: 242
X-Cache: Error from cloudfront
Via: 1.1 404e3b476748051f3f9bc690b72173b4.cloudfront.net (CloudFront)
X-Amz-Cf-Id: 3yUNjkFQHC83FlbEwVMBSddpQND_4GbXauyeTtDyKawS6GzftUwXRA==
I'm also restarting my server "service nginx restart" but still nothing happen
Here is my CloudFront which is the default setting
Everything work fine in my dev env
I couldn't figure why this happening. Please help
Thanks in advance
Problem solved by clean install the server, upgrade ruby to 2.2.1 plus.. looks like the issue come from the server itself. my setting before was fine..

Unable to access certain file types via Rails public folder on Heroku

We're hosting a Rails app on Heroku, and having some trouble serving some static assets out of the public folder. (I know, this isn't recommended. We actually use CloudFront with a custom origin of our main application so we're getting the benefit of a CDN still. But that's irrelevant for this issue.)
Some assets serve up fine and exactly as expected. Ex: /404.html, /favicon.png
Others return an HTTP 406 error: /video-js/swf/video-js-4.1.0.swf
Rails 4.1.1
Ruby 2.1.2
The rails_12factor gem is present.
production.rb file sets config.serve_static_assets = true
The file definitely exists.. Using the console on Heroku:
File.size("/app/public/video-js/swf/video-js-4.1.0.swf")
=> 14059
But when I try to access the file, I get an HTTP 406 Not Acceptable response
curl -I http://my-rails-application.com/video-js/swf/video-js-4.1.0.swf
returns:
HTTP/1.1 406 Not Acceptable
Content-length: 0
Content-Type: text/html; charset=utf-8
Date: Wed, 04 Jun 2014 02:25:37 GMT
Status: 406 Not Acceptable
X-Request-Id: d184b097-7326-49cb-ad05-539459f7df08
X-Runtime: 0.532988
Connection: keep-alive
I tried adding a Mime Type for swf files (Mime::Type.register "application/x-shockwave-flash", :swf) and now I get a 404 instead of a 406, but that's still not very useful.
To recap, html, png, jpg, ico, and txt files all are served perfectly. swf, ttf, woff and a few others aren't being served out of the public folder.
What could cause some file types in the public folder to work properly, but not others?

Robots.txt file on Rails heroku app not updating

I've got a rails app hosted on Heroku for which I'm trying to update the robot.txt file.
The local file, which is at /public/robots.txt, reads:
User-agent: *
Disallow: /admin/
However when I deploy the app to Heroku, the robots file is seemingly not updated. The remote version reads:
# See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file
#
# To ban all spiders from the entire site uncomment the next two lines:
User-agent: *
Disallow: /
The live url is at http://www.cowboypicks.com/robots.txt.
Running curl -I http://www.cowboypicks.com/robots.txt yields:
HTTP/1.1 200 OK
Age: 2317078
Cache-Control: public, max-age=2592000
Content-length: 200
Content-Type: text/plain
Date: Wed, 30 Apr 2014 17:01:43 GMT
Last-Modified: Thu, 03 Apr 2014 14:21:08 GMT
Status: 200 OK
X-Content-Digest: 10c5b29b9aa0c6be63a410671662a29a796bc772
X-Rack-Cache: fresh
Connection: keep-alive
Indicating the file hasn't been updated since 3 April, however it has been updated today (30 April). Even stranger, when I run heroku run bash followed by cat public/robots.txt I get:
User-agent: *
Disallow: /admin/
Indicating the file is being updated on Heroku but it's showing an older (I assume cached) version for some reason. There is some caching on the app using dalli/memcache, but I wouldn't have thought that would affect static files? Any ideas on how I could further debug the problem?
It turned out that Dalli had indeed been caching the robots.txt file in production. The expiry date was set in production.rb with the line:
config.static_cache_control = "public, max-age=2592000"
Running the following from the rails console flushed the cache and sorted the problem:
Rails.cache.dalli.flush_all

Why is my js+css not compressed in production on Rails + Heroku?

I am running my producction environment with following settings, and it appears that it is minifying but is not gzipping/compressing the response.
# Disable Rails's static asset server (Apache or nginx will already do this)
config.serve_static_assets = false
# Compress JavaScripts and CSS
config.assets.compress = true
# Don't fallback to assets pipeline if a precompiled asset is missed
config.assets.compile = false
# Generate digests for assets URLs
config.assets.digest = true
Here is my js file, and the headers dont contain gzip or deflate???
$ curl -I http://sctest-perf.herokuapp.com/assets/application-1d21d488644b11e5610fa26bacdbc868.js
HTTP/1.1 200 OK
Age: 0
Cache-Control: public, max-age=31536000
Content-length: 213394
Content-Type: application/javascript
Date: Fri, 08 Jun 2012 20:34:58 GMT
Etag: "1d21d488644b11e5610fa26bacdbc868"
Last-Modified: Wed, 30 May 2012 16:38:32 GMT
Status: 200 OK
X-Content-Digest: 914bc6f80b0619be63c1302821ccc24a082ace53
X-Rack-Cache: miss, store
X-Request-Id: 76cb22ef23b73c440878569eec42ed4d
X-Runtime: 0.001314
X-Ua-Compatible: IE=Edge,chrome=1
Connection: keep-alive
You need to edit the config.ru file, located in your project root:
require ::File.expand_path('../config/environment', __FILE__)
# Add beautifully gzipped responses
use Rack::Deflater
run YourApp::Application
You could also try using one of these gems which are supposed to help optimize the serving of assets process further.
https://github.com/romanbsd/heroku-deflater
https://github.com/mattolson/heroku_rails_deflate
If I'm not mistaken using use Rack::Deflater also compresses images which wastes resources and isn't useful.

Resources