Caching Rails assets with NGinx

Nginx is a very popular high performance web server. It’s very easy to configure and many Ruby on Rails developers are using it as a load balancer for Rails applications. Usually the setup looks like this:

Screen Shot 2015-08-18 at 10.13.19

Typically the rails application is running on Mongrel, Unicorn or Puma. These ruby application servers can deliver static assets (.png, .jpg, .js, .css) as well, but there are not really optimised for that. Nginx is much faster in delivering static assets like images, javascript and css files. Ideally your ruby application server should only handle requests to ruby controllers and generate dynamic content.

This is the Nginx configuration for load balancing between 2 ruby application servers, or any other application servers:

 
upstream unicorns {
  server 192.168.1.11:8080;
  server 192.168.1.12:8080;
}
 
server {
  listen 80;
  location / {
        proxy_redirect off;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        proxy_pass http://unicorns;
    }
}

At Rails all static assets are delivered under the route “/assets/”. Now we will tell Nginx to cache files from “/assets/” for 120 minutes. For that we need this 2 lines at the beginning of our nginx.conf file.

proxy_cache_path /tmp/nginx levels=1:2 keys_zone=veye_zone:10m inactive=120m;
proxy_cache_key "$scheme$request_method$host$request_uri";

The first line defines the directory where the files for the cached asserts should be stored. In this case it would be “/tmp/nginx”. We define the name space “veye_zone” with 10 MB for this cache. The 2nd line defines the structure of the cache key, which has to be unique.

Now we can add another location for “/assets” to our configuration.

server {
  listen 80;

  location /assets/ {
        proxy_redirect off;
        proxy_pass_header Cookie;
        proxy_ignore_headers Set-Cookie;
        proxy_hide_header Set-Cookie;
        
        proxy_cache veye_zone;
        proxy_cache_valid 200 302  120m;
        proxy_cache_valid 404      1m;

        proxy_pass http://unicorns;
  }

  location / {
        proxy_redirect off;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        proxy_pass http://unicorns;
    }
}

The 3 most important lines for the caching are these here:

        proxy_cache veye_zone;
        proxy_cache_valid 200 302  120m;
        proxy_cache_valid 404      1m;

They reference to the “veye_zone” cache, which we defined in the top of our nginx.conf. The 2nd line tells Nginx to cache everything with a response code of 200 and 302 for 120 minutes. And everything with a response code of 404 for 1 minute.

All HTTP requests to “/assets/” first will go to one of the ruby application servers, but the responses will be cached at Nginx for 120 minutes. All further requests to “/assets/” will not hit the ruby app servers, because Nginx can deliver the content from the cache.

The beauty at this setup is that it’s seamless to the deployment of the ruby application. The deployment process doesn’t have to copy the assets files to the Nginx server. Nginx is just automatically caching all assets.

4 thoughts on “Caching Rails assets with NGinx

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s