Jack Moore

Email: jack(at)jmoore53.com
Project Updates

Rock the Cache-bah

24 Jan 2022 » web, html, nginx, configuration, docker, load balancing

Title for this post comes from the song Rock the Casbah. This post covers speeding up my static blog via Nginx caching and other page optimizations. I have the blog and I need it to be fast. Why? Nobody likes a slow website.

Where to start

Well it’s hard to tell where to optimize if you don’t know where you currently stand. That’s why I decided to check my score with a few PageSpeed Insights tests first. I used Google’s PageSpeed, Solarwinds’ Pingdom, and attempted to use Cloudflare’s Speed Test Tool (which wasn’t working).

Upon inital run (with no optimizations), I was clocking in around an F ranking. Everything and I mean everything was clocking in in the RED. First Contentful Paint was about 5 seconds on mobile, time to interactive was close to 8 seconds, and overall resources were not looking good. Even the desktop site was reporting slow. This is a static site, everything should be fast!

I wasn’t happy with the initial results, but they at least gave me a jumping off point and some of the sites even provided where optimizations could be made. The recommendations span from the client to the server and are listed below:

1) Moving CSS and Javascript

One of the first things recommended and that I saw with developer tools even was that content loaded from third parties was causing a hold up on the page load. I moved all third party libraries first party to the server by copying the minified JS/CSS to the source of the blog, so instead of reaching out to a CDN for fonts/stylesheets/javascript, now the server could serve all of these resources when the page was loaded. (See the html code snippet below, and note none of the js/css is third party. Everything is served from the same source, the root of this site.)

This next recommendation was to move javascript assets and CSS Stylesheets to load at the end of the page to prevent Javascript from blocking the page from loading. This was an easy optimization as I had already moved most of the Javascript to the bottom of the body.

At first with moving the rest of the css to the end of the body, I actually saw a “lower” performance due to the page rendering. I’m not saying the page didn’t load fast, because it definitely did, but at what cost? Essentially the page would load all the content in the body, then process the js/css which would pretty much re-jumle all the content on the page. This was a terrible user experience and a complete eye sore, so I moved the necessary bootstrap css files to the top and left everything else at the bottom to prevent this jumble from occurring again.

Below is what the CSS/JS optimizations looked like after modification (note these changes, even as small as they are, durastically improved the initial render time of the site):

    <!-- Bootstrap core CSS -->
    <link href="/static/css/bootstrap.min.css" rel="stylesheet">
    <!-- Fonts -->
    <link href="/static/css/cyrillic-ext.css" rel="stylesheet" type="text/css">

    <!-- 

        Body of the page HERE!
        
    -->

    <!-- Font awesome icons -->
    <link href="/static/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-T8Gy5hrqNKT+hzMclPo118YTQO6cYprQmhrYwIiQ/3axmI1hQomh7Ud2hPOy8SP1" crossorigin="anonymous">
    <!-- syntax highlighting CSS -->
    <link rel="stylesheet" href="/static/css/syntax.css">
    <!-- Custom CSS -->
    <link rel="stylesheet" href="/static/css/super-search.css">
    <link rel="stylesheet" href="/static/css/thickbox.css">
    <link rel="stylesheet" href="/static/css/projects.css">
    <link rel="stylesheet" href="/static/css/main.css">

    <!-- Bootstrap core JavaScript -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="/static/js/jquery.min.js"></script>
    <script src="/static/js/jquery-migrate-1.2.1.min.js"></script>
    <script src="/static/js/bootstrap.min.js"></script>
    <script src="/static/js/super-search.js"></script>
    <script src="/static/js/thickbox-compressed.js"></script>
    <script src="/static/js/projects.js"></script>

Nginx and Server Side Optimizations

As I use NGINX to serve the static content, there were a few changes I made to the nginx.conf file as well as to the default.conf file where the site was being served from. These included: using gzip for assets, and adding caching for content.

GZIP

Reducing the size of all the files the browser needs will make the website faster because the browser will have to download less, hence using gzip for compressing those served files will speed up page requests.

The NGINX gzip module compresses the files on the fly before sending them to the browser. For more on Gzip, see this post from Digital Ocean on configuring gzip within NGINX, or the NGINX documentation on gzip and compression for the full details.

Below are the optimizations I found to be the most helpful. Within the nginx.conf/http block I have configured the gzip options like the following:

http{

    # other configurations here...

    gzip on;

    gzip_vary on;
    gzip_static 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/javascript text/xml application/xml application/xml+rss text/javascript;
}

Cache Policies

Caching was the first thing that came to mind when I thought of optimizations for page loading especially on a static website. I have always been a bit timid on caching as I never fully understood how simple an LRU Cache is, however nginx pretty much makes caching easy to configure.

The Nginx documentation provides a great guide on caching which I used along with Stack Overflow answers to fine tune my caching configuration.

Below is the configuration I used for caching assets, which can be found within the location block of the sites-available/default/server block as seen below:

server {

    # other configurations here...

    location ~* ^.+\.(?:css|cur|js|jpe?g|gif|htc|ico|png|html|xml|otf|ttf|eot|woff|woff2|svg)$ {
            access_log off;
            expires 30d;
            add_header Cache-Control max-age=31536000;
            add_header Cache-Control public;

            ## No need to bleed constant updates. Send the all shebang in one
            ## fell swoop.
            tcp_nodelay off;

            ## Set the OS file cache.
            open_file_cache max=3000 inactive=120s;
            open_file_cache_valid 45s;
            open_file_cache_min_uses 2;
            open_file_cache_errors off;
    }
}

It was discussed in the comments of the SO answer the above is not a preferred solution due to what I concluded was client expiration problems (note the content expires on the browser in a year). I may revisit this. Also for serving static assets with an efficient cache policy, see this post from Google.

Post Optimization

After these optimizations were complete, the site went from failing (50% score with close to a 5 second load time), to a 92% score on mobile (1.6s page load time), and a 99% score (.6 second page load time) on desktop. Although there’s always more work to be done, I am happy for the time being with the optimizations to speed up the blog.

© Jack Moore