Compressing rails assets and nginx gzip - ruby-on-rails

Do I have to configure nginx to compress assets (gzip set to on) if I have compressed rails assets with rake assets:precompile? I mean does it make sense or not? Will performance better or worse? Thank you!

Do rake assets:precompile and you have to configure nginx for send gzip version of files, i use this configuration.
user www-data www-data;
worker_processes 4;
pid /var/run/nginx.pid;
events{
worker_connections 2048;
use epoll;
}
http{
include mime.types;
default_type application/octet-stream;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
server_tokens off;
server_name_in_redirect off;
ignore_invalid_headers on;
gzip off;
sendfile on;
upstream reverse-proxy{
server 127.0.0.1:3000;
server 127.0.0.1:3001;
server 127.0.0.1:3002;
server 127.0.0.1:3003;
}
server{
listen 80;
server_name _;
root /home/www-data/my_website/public;
client_max_body_size 10M;
client_body_buffer_size 512k;
location ~ ^/assets/ {
gzip_static on;
add_header Cache-Control public;
expires 4w;
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_disable "MSIE [1-6]\.";
gzip_comp_level 6;
gzip_types application/x-javascript text/css text/html image/x-icon image/png image/jpeg image/gif;
}
location / {
try_files $uri #ruby;
}
location #ruby {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://reverse-proxy;
}
}
}

No, you do not. They are not the same kind of compression. When you run rake assets:precompile, all you're really doing is joining a bunch of files into one file and dumping it to the disk. Actually, according to the official documentation, it is two files:
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.
This is important for you, because it allows you to use gzip, if you want, but it does not force you to do so. Gzip compression, which is real compression (not just concatenating files) reduces the amount of data you have to transfer, but at the expense of processor power (compressing and decompressing). It is likely to fairly dramatically improve your site, depending on page sizes and your (and your user's) hardware.

Here is a complete configuration(I am using it for my site):
GENERAL CONFIGURATION
http {
passenger_root /usr/local/lib/ruby/gems/1.9.1/gems/passenger-4.0.5;
passenger_ruby /usr/local/bin/ruby;
include mime.types;
default_type application/octet-stream;
server_tokens off;
sendfile on;
keepalive_timeout 70;
gzip on;
gzip_http_version 1.1;
gzip_disable "msie6";
gzip_vary on;
gzip_min_length 1100;
gzip_buffers 64 8k;
gzip_comp_level 3;
gzip_proxied any;
gzip_types text/plain text/css application/x-javascript text/xml application/xml;
add_header Strict-Transport-Security "max-age=16070400; includeSubdomains";
add_header X-Frame-Options DENY;
limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;
include /opt/nginx/conf/nginx_host.conf;
}
Content of /opt/nginx/conf/nginx_host.conf;
HOST CONFIGURATION
server {
listen 80;
server_name *.domain.com;
root APP_PATH/current/public;
passenger_enabled on;
access_log off;
error_log /dev/null;
# Cross domain webfont access
location ~* \.(?:ttf|ttc|otf|eot|woff|font.css)$ {
add_header "Access-Control-Allow-Origin" "*";
expires 1M;
access_log off;
add_header Cache-Control "public";
}
location ~* \.(ico|css|gif|jpe?g|png)(\?[0-9]+)?$ {
expires max;
}
location ~ ^/(assets|uploaded_assets|system)/ {
root /home/travelobd/rails_apps/travelobd/current/public;
gzip_static on; # to serve pre-gzipped version
expires max;
add_header Cache-Control public;
}
}
For serving assets:
server {
listen 80;
server_name static.domain.com;
root APP_PATH/current/public;
location / {
if ($request_filename ~ "\.(jpg|css|gif|png|swf|ico|js)$") {
break;
}
return 404;
}
}

Yes, you should if you want to improve performance.
Simply add the following block to your site configuration:
location ~ ^/(assets)/ {
root /path/to/public; # CHANGE THIS
gzip_static on; # to serve pre-gzipped version
expires max;
add_header Cache-Control public;
}
Change the root path in the configuration. That is all there is to it.
RecommendationFromDocumentation™: http://guides.rubyonrails.org/asset_pipeline.html

What worked for me was configuring Nginx:
location ~ ^/(assets)/ {
gzip_static on;
}
Then in application.rb:
config.middleware.insert_before(Rack::Sendfile, Rack::Deflater)
# Compress JavaScripts and CSS.
config.assets.compress = true
config.assets.js_compressor = Uglifier.new(mangle: false)

Related

How to Optimize and Scale Ruby on Rails App with Nginx and Passenger

I have an app in production which uses Ruby on Rails with Nginx and Passenger, the performance is good at the start but as the time goes by (after an hour or more) it slows down, I need to restart the Nginx for it to increase its performance again. May I know how to make it more optimize and scalable and avoid in keep on restarting. Thanks, guys need your help so bad.
There are some settings you can do to optimize your Nginx server.
If you have root access to your server and have Nginx correctly added, you can consider some changes.
1) Run sudo vim /etc/nginx/nginx.conf & consider these settings based on what are your needs (don't replace the whole code into your server as some of the default setting are not here. Just add ones you neeed):
user www-data;
worker_processes 4;
pid /run/nginx.pid;
events {
worker_connections 768;
multi_accept on;
use epoll;
}
worker_rlimit_nofile 40000;
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
client_body_timeout 500s;
client_header_timeout 500s;
keepalive_timeout 500s;
send_timeout 300s;
types_hash_max_size 2048;
# server_tokens off;
client_max_body_size 100000M;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# SSL Settings
##
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
##
# Logging Settings
##
access_log off;
#access_log /var/log/nginx/access.log;
#error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
gzip_disable "msie6";
gzip_vary on;
# gzip_proxied any;
gzip_comp_level 2;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
gzip_min_length 10240;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
gzip_disable "MSIE [1-6]\.";
}
You can change the numbers based on your application and needs.
2) Run sudo vim /etc/nginx/sites-enabled/default & consider these settings based on what are your needs (don't replace the whole code into your server as some of the default setting are not here. Just add ones you neeed):
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
passenger_enabled on;
# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
location ~* \.(jpg|jpeg|png|gif|ico)$ {
access_log off;
log_not_found off;
expires 30d;
}
location ~* \.(js)$ {
access_log off;
log_not_found off;
expires 150d;
}
location ~* \.(css)$ {
access_log off;
log_not_found off;
expires 150d;
}
}
You can change the numbers based on your application and needs.
Remember to restart ngnix after changes.
Again be careful to what you add or remove and again DO NOT copy & paste the whole code as some default settings are not here.
One other thing would be take a look at your logs & tmp files/folder as you can eliminate logs to take less memory and space. You can also take a look tmp folder and settings.
You can also consider (recommended) doing caching in your views. As you know rails has Fragment and Russian doll caching. Caching will always help boosting response time.
If you are not familier with caching, there is also something called progressive rendering. You can use gem 'progressive_render' and watch this toturial.
Hope it helps.

Nginx seem to be ignoring try_files order

Not sure if I'm misunderstanding how try_files work, or if there's something wrong with my config. I'm running Rails on Puma behind Nginx. I'm trying to serve items in my /public folder, after which it should send the requests to Puma.
So, if I go to
https://domain.com/sitemap.xml
it should serve /var/www/live/current/public/sitemap.xml. Then, https://domain.com/rails_index_page should be served from Puma.
The latter works fine, and I can access https://domain.com/public/sitemap.xml, but I would like to access it via https://domain.com/sitemap.xml
My config file looks as follows:
upstream live {
server unix:///var/www/live/shared/puma.sock;
}
server {
client_body_buffer_size 10K;
client_header_buffer_size 1k;
client_max_body_size 8m;
large_client_header_buffers 4 16k;
client_body_timeout 12;
client_header_timeout 12;
keepalive_timeout 15;
send_timeout 10;
server_tokens off;
listen 443;
ssl on;
ssl_certificate /etc/nginx/ssl/ssl-bundle.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
ssl_session_cache shared:SSL:20m;
ssl_session_timeout 10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;
ssl_prefer_server_ciphers on;
server_name domain.com; # change to match your URL
root /var/www/live/current/public; # I assume your app is located at this location
try_files $uri #live;
location #live {
add_header Strict-Transport-Security "max-age=31536000";
gzip on;
gzip_static on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 8;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
proxy_pass http://live; # match the name of upstream directive which is defined above
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ~ ^/assets/ {
expires 1y;
add_header Cache-Control public;
root /var/www/live/current/public;
gzip on;
gzip_static on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 8;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
add_header Last-Modified "";
add_header ETag "";
}
set $rootUrl "/var/www/live/current";
location ~* \.(?:ico)$ {
root $rootUrl;
expires 30d;
add_header Cache-Control public;
access_log off;
}
# css and js are tokenized
location ~* \.(?:css|js) {
root $rootUrl;
expires max;
add_header Cache-Control public;
access_log off;
}
# nginx gzip_static does not add Vary header for fonts.
location ~* \.(?:eot|ttf|svg)$ {
root $rootUrl;
expires max;
add_header Access-Control-Allow-Origin *;
add_header Vary Accept-Encoding;
add_header Cache-Control public;
access_log off;
}
# woff fonts should not be zipped.
location ~* \.(?:woff)$ {
root $rootUrl;
add_header Access-Control-Allow-Origin *;
expires max;
add_header Cache-Control public;
access_log off;
}
# tokenized images can be cached forever
location ~* "\.([a-z0-9]{8})\.(?:gif|png|jpe?g)$" {
root $rootUrl;
expires max;
add_header Cache-Control public;
access_log off;
add_header Access-Control-Allow-Origin *;
}
# non tokenized images only cache for 1 week as they are in my context subject to change.
location ~* \.(?:gif|png|jpe?g)$ {
add_header Access-Control-Allow-Origin *;
root $rootUrl;
expires 1w;
add_header Cache-Control public;
access_log off;
}
}
I'm sure the config file can be updated/optimised quite a bit, so please don't shout at me toooo much for that. :)
Does adding a default location block help? Something like
location / {
try_files $uri #live;
root ... ;
}
Try files is valid in the server context, but I don't know what order location directives are matched (and fall through to the server default)
Apologies for no formatting, I'm on mobile, I'll fix it up if it helps.

Unable to cache static contents with nginx for ruby on rails application

I am using Ruby On Rails application with Rails 4.1 in digitalocean droplet. I have installed nginx with passenger and my application working perfect over here.
Now I want to cache static content with nginx and I have did following configuration for nginx.conf file. I don't know what is wrong over here. Please give me suggestion for working the same.
My nginx.conf file:
user www-data;
worker_processes 4;
pid /run/nginx.pid;
events {
worker_connections 768;
# multi_accept on;
}
http {
log_format cache '***$time_local '
'$upstream_cache_status '
'Cache-Control: $upstream_http_cache_control '
'Expires: $upstream_http_expires '
'"$request" ($status) '
'"$http_user_agent" ';
access_log /var/log/nginx/cache.log cache;
proxy_cache_path /data/nginx/cache keys_zone=one:10m levels=1:2 loader_threshold=300 loader_files=200 max_size=200m;
proxy_temp_path /data/nginx/cache/tmp;
server {
listen 80;
proxy_cache one;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto http;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://api.xyz.com;
}
location ~ ^/(stylesheets|javascripts|images|system/avatars) {
expires 720h;
}
}
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# Logging Settings
##
# set client body size to 20M #
client_max_body_size 20M;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
gzip_disable "msie6";
# gzip_vary on;
gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
##
# nginx-naxsi config
##
# Uncomment it if you installed nginx-naxsi
##
# include /etc/nginx/naxsi_core.rules;
##
# Phusion Passenger config
##
# Uncomment it if you installed passenger or passenger-enterprise
##
passenger_root /usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini;
passenger_ruby /usr/local/bin/ruby;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Please let me know if you need anything else for caches static content with nginx.
Since Rails 3.1, it use assets precompile in production environment. I use this for my rails app in nginx:
location ~ ^/assets/ {
expires 1y;
add_header Cache-Control public;
add_header ETag "";
break;
}
Read about it here: http://guides.rubyonrails.org/v4.1.8/asset_pipeline.html

After deploy I see standard nginx's "It works!"

I've deployed rails app with Capistrano to VPS, and when I try to access it with "APP_NAME.com", I see standard Nginx's "It works!" page.
I've tried to remove index.html file from /var/www folder, now I see folders in it: apps, log and tmp.
In nginx.conf I have:
user nginx web;
pid /var/run/nginx.pid;
error_log /var/www/log/nginx.error.log;
events {
worker_connections 1024;
accept_mutex off;
use epoll;
}
http {
include mime.types;
types_hash_max_size 2048;
server_names_hash_bucket_size 64;
default_type application/octet-stream;
access_log /var/www/log/nginx.access.log combined;
sendfile on;
tcp_nopush on; # off may be better for *some* Comet/long-poll stuff
tcp_nodelay off; # on may be better for some Comet/long-poll stuff
gzip on;
gzip_http_version 1.0;
gzip_proxied any;
gzip_min_length 0;
gzip_vary on;
gzip_disable "MSIE [1-6]\.";
gzip_proxied expired no-cache no-store private auth;
gzip_comp_level 9;
gzip_types text/plain text/xml text/css
text/comma-separated-values
text/javascript application/x-javascript
application/atom+xml;
upstream app_server {
server unix:/var/www/apps/APP_NAME/socket/.unicorn.sock fail_timeout=0;
}
server {
pagespeed on;
pagespeed FileCachePath /var/ngx_pagespeed_cache;
location ~ "\.pagespeed\.([a-z]\.)?[a-z]{2}\.[^.]{10}\.[^.]+" {
add_header "" "";
}
location ~ "^/ngx_pagespeed_static/" { }
location ~ "^/ngx_pagespeed_beacon$" { }
location /ngx_pagespeed_statistics {
allow 127.0.0.1; allow 5.228.169.73; deny all;
}
location /ngx_pagespeed_global_statistics {
allow 127.0.0.1; allow 5.228.169.73; deny all;
}
pagespeed MessageBufferSize 100000;
location /ngx_pagespeed_message {
allow 127.0.0.1; allow 5.228.169.73; deny all;
}
location /pagespeed_console {
allow 127.0.0.1; allow 5.228.169.73; deny all;
}
charset utf-8;
listen 80 default deferred; # for Linux
client_max_body_size 4G;
server_name _;
keepalive_timeout 5;
root /var/www/apps/APP_NAME/current/public;
try_files $uri/index.html $uri.html $uri #app;
location ~ ^/(assets)/ {
root /var/www/apps/APP_NAME/current/public;
expires max;
add_header Cache-Control public;
}
location #app {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server;
}
error_page 500 502 503 504 /500.html;
location = /500.html {
root /var/www/apps/APP_NAME/current/public;
}
}
}
Am I missing something in nginx.conf or in other files?
Also, when I stop nginx server, it doesn't make sense, I see the same page.
I'm not good in deploying apps to server, it's my first time without Heroku, so I don't know, what exactly you need to know, to help in my problem. So, if you need any additional info, ask, I'll add it to question.
Thanks!
So, I've found the solution from this answer. The problem was with Apache web server, which was running in background and prevent Nginx to run on 80 port.
I've stopped Apache server and restart Nginx, and everything now works ok:
sudo apachectl stop
sudo restart nginx
Your must use passenger and set in nginx config something like this:
http {
passenger_root /home/deployer/.rvm/gems/ruby-1.9.3-p327/gems/passenger-3.0.18;
passenger_ruby /home/deployer/.rvm/wrappers/ruby-1.9.3-p327/ruby;
...
or use HTTP server for Rack, as example Unicorn, and set in nginx config:
upstream app_server {
server unix:/path/to/.unicorn.sock fail_timeout=0;
...
server {
proxy_pass http://app_server;
...

Ruby process running at max CPU usage and not serving any page - Ubuntu Nginx Unicorn Rails Configuration

I am following this guide to setup Rails service using Nginx and Unicorn http://ariejan.net/2011/09/14/lighting-fast-zero-downtime-deployments-with-git-capistrano-nginx-and-unicorn/
When I started Nginx without Unicorn I get 502 Bad Gateway error
and as soon as I start the Unicorn server using the following command unicorn_rails -c config/unicorn.rb -D the request times out and I get 504 Gateway Time-out error. The CPU usage for ruby process is 100% and seems like something is stuck in a loop but I do not understand what is happening
nginx/1.2.6 (Ubuntu)
This is my /etc/nginx/nginx.conf
user ubuntu staff;
# Change this depending on your hardware
worker_processes 4;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
multi_accept on;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay off;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
gzip on;
gzip_disable "msie6";
# gzip_vary on;
gzip_proxied any;
gzip_min_length 500;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml applicat
ion/xml+rss text/javascript;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
and this is my /etc/nginx/sites-available/default
upstream home {
# fail_timeout=0 means we always retry an upstream even if it failed
# to return a good HTTP response (in case the Unicorn master nukes a
# single worker for timing out).
# for UNIX domain socket setups:
server unix:/tmp/home.socket fail_timeout=0;
}
server {
# if you're running multiple servers, instead of "default" you should
# put your main domain name here
listen 80;
# you could put a list of other domain names this application answers
server_name patellabs.com;
root /home/ubuntu/apps/home/current/public;
access_log /var/log/nginx/home_access.log;
rewrite_log on;
location / {
#all requests are sent to the UNIX socket
proxy_pass http://home;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
}
# if the request is for a static resource, nginx should serve it directly
# and add a far future expires header to it, making the browser
# cache the resource and navigate faster over the website
# this probably needs some work with Rails 3.1's asset pipe_line
location ~ ^/(images|javascripts|stylesheets|system)/ {
root /home/ubuntu/apps/home/current/public;
expires max;
break;
}
}

Resources