Serving Compressed Content with Rails and AWS Elastic Beanstalk

AWS Ruby on Rails

When it comes to loading time of your web application speed is always a major aspect. A simple web site that loads very fast is the best user experience. Speed is always in style. If you wonder whether your web site is fast or slow, you can always ask Google for that. Simply go to the Google PageSpeed Insights, enter your website URL and they will analyze it for you.

That handy online tool checks your website against a list of bad practices and creates an overall score and detailed report for you. One of the metrics it uses to measure your web site speed is compression. Compression normally shrinks a text file by a factor. Given most web sites receive more hits from mobile devices than desktop browsers, shrinking your content becomes of a great importance. So let’s see how to make your web application smaller and faster.

Why AWS Elastic Beanstalk?

I do not have to manage infrastructure. I focus on application development instead.

AWS Elastic Beanstalk (EB) is an easy-to-use service for deploying and scaling web applications. You really don’t need a costly Ops team to manage your infrastructure. Even a web developer with zero experience in deploying applications can execute a smooth go live with AWS EB. The experience is very similar to other popular PaaS solutions like Heroku or OpenShift but the running costs are lower. There is no additional charge for Elastic Beanstalk - you pay only for the AWS resources needed to store and run your applications.

Serving Compressed Content

You have two distinct problems to solve:

  1. Serving your static content.
  2. Serving your dynamic content.

Static Content

Here you have a number of options. Just to name a few:

  1. Use of Content Delivery Network (CDN).
  2. Use of front-end proxy to handle the compression.
  3. Use of web server to serve the pre-compressed assets.

The best approach for large-scale apps would be using a CDN for your static assets. However, for smaller apps, the approach I usually go for is much simpler: do nothing. Yes, job done out of the box. Thank you, Amazon! Thank you, Rails team! But enough with the kudos and let’s look under the hood.

As static assets may change only between deployments you have to setup everything during each deployment. There are two tasks on the to-do list here: (1) compress the assets and (2) serve the compressed version.

1. Compress the assets

Luckily the Rails asset pipeline handles this one for us by default. By default, gzipped version of compiled assets will be generated, along with the non-gzipped version of assets. If you ssh to any of your EC2 instances you can verify that.

$ ls public/assets/

As I already said - nothing to do at this step.

2. Serve the compressed version of the assets

AWS EB handles this one for us by default. When you create your application environment, a Nginx configuration file is created for you: /etc/nginx/conf.d/webapp.conf (could be different in different versions of EB) with the following configuration inside:

  location /assets {
    alias /var/app/current/public/assets;
    gzip_static on;
    gzip on;
    expires max;
    add_header Cache-Control public;

  location /public {
    alias /var/app/current/public;
    gzip_static on;
    gzip on;
    expires max;
    add_header Cache-Control public;

Notice here the gzip_static setting which tells Nginx reverse proxy to serve compressed version of the assets. So nothing to do in here as well.

We managed to serve compressed static content with zero effort.

Dynamic Content

Let’s take a look at compressing dynamic content. Here again we have several options and just to name a couple:

  1. Rack::Deflater Middleware.
  2. Let a reverse proxy handle compression.

Using any of these approaches is better off to serving uncompressed content. The Rack::Deflater middleware compresses responses at runtime using deflate or gzip. It reduces the size of your responses (HTML or JSON) by a factor. Still I don’t want my application server to be worrying about compression. I would prefer to delegate that job to a reverse proxy. On AWS Elastic Beanstalk it is quite easy to configure the Nginx reverse proxy to compress your application dynamic content. You can achieve that using ebextensions to create additional Nginx configuration files which will be included in the main configuration file like this:

include /usr/share/nginx/modules/*.conf;

That line from the main config file causes all conf files in the /etc/nginx/conf.d/ directory to be included in the main Nginx configuration. You add a new configuration file by creating a file under the .ebextensions folder in your application. For example, you create a file .ebextensions/01_gzip.conf like this:

      mode: "644"
      owner: "root"
      group: "root"
      content: |
        gzip on;
        gzip_types text/plain text/html application/json;

    command: service nginx reload

That file will create a 01_gzip.conf file inside the Nginx conf.d folder that will be included by the main configuration file. The container command will make Nginx reload its configuration. As order matters, you may want to prefix your configuration files with a number to be certain of their order of inclusion. As my gzip.conf file is my first and only one I have named it 01_gzip.conf.

Back to serving gzipped content. You have two options that you have to configure on Nginx to compress your application dynamic content - gzip on; and gzip_types. Since we already serve compressed assets using gzip_static on here you may want to list only your dynamic content types. There are a number of other gzip options you may want to play around with here but those two are enough for your reverse proxy to start serving gzipped content. That is how you use EB extensions to configure your environment from your application source code.


With minimal efforts we were able to shrink our application content by a factor. Users love our web application even more than before. Bots love it. We just made the whole world of humans and machines a better place :)