With newer versions of Ghost and the addition of the membership feature, be careful modifying the nginx config. Having an aggressive caching policy might affect member sessions.

Site speed is important for many reasons, one of the most important being that it is used by Google's algorithm to rank pages. It is also important to user experience. Pages with a longer load time tend to have higher bounce rates and lower average time on page. Longer load times have also been shown to negatively affect conversions.

Now that we have seen why site speed is important let's take a look at how it can be improved:

Things to consider:

  • Enable compression
  • Minify CSS, JavaScript, and HTML
  • Reduce redirects
  • Remove render-blocking JavaScript
  • Leverage browser caching
  • Improve server response time
  • Use a content distribution network
  • Optimize images

In this article we will focus on improving page speed on the server side. More specifically on Nginx.


Nginx is a powerful web server designed for maximum performance and stability, reverse proxying, caching, load balancing, media streaming, and more.

So let's see how we can configure Nginx to improve site speed.

Enable compression

A website's load time depends on the size of all of the files that have to be downloaded by the browser. Reducing the size of files to be transmitted can make the website load faster.

gzip comes handy for this task. Nginx can be configured to use gzip to compress files it serves. As mentioned before the smaller the amount of data being transferred between the web server and browser the better.

To configure Nginx to serve compressed files we have to edit the nginx.conf file. To change the Nginx gzip configuration, open this file in nano or your chosen text editor.

The nginx.conf should be found under the following path:


After opening the configuration file, search for the gzip settings section. Add the following lines of code to enable compression for all the file types in the gzip_types part.

. . .
# `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_min_length 256;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype image/svg+xml image/x-icon;
. . .

Save and close the file to exit. To enable the new configuration, restart Nginx:

sudo service nginx restart

Google's advice on enabling compression.

Leverage browser caching

Nginx is really good at serving static files. With a default install of Ghost, Nginx will proxy all requests to Node.js to be handled, even requests for the assets like images, JS and CSS files. First we have to configure Nginx to serve these files itself.

First we will change the same nginx.conf file that we edited earlier. Add the following part fo define the upstream for the Ghost blog, this should go before the include definitions:

upstream ghost {
  keepalive 64;

include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;

Now open up the nginx configuration file for your ghost blog. This should be found here:


Add the following lines to overwrite the default behavior requesting assets:

location ^~ /assets/ {
    root /var/www/ghost/content/themes/theme_name;

The /assets/ directory is where Ghost has all of the blog's JS, CSS and fonts. With this new location block we're telling Nginx that any request files within /assets/ can be served out of the path given(root).

This path has to be updated to point to the theme folder. Don't forget to change it in case you change your theme.

Now we do the same thing for the images:

location ^~ /content/images/ {
    root /var/www/ghost;

Now Nginx will now host these files directly and not pass the request to Node.

To enable caching we have to add the below lines to nginx.conf file:

proxy_cache_path /home/cache/ghost_cache levels=1:2 keys_zone=ghost_cache:60m max_size=300m inactive=24h;
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_methods GET HEAD;

The specified directory(/home/cache) has to exist. The levels specifies that Nginx should split the cache files over 2 subdirectories inside the cache folder. The keys_zone specifies the name of the cache and the size in Mb for the memory location where cache keys are stored. The max_size defines the maximum size on disk that cached files can take up and inactive specifies how long the cache manager should wait to remove a file from the cache after it was last accessed.

We configured the cache now we have to make Ghost use it. Open the ghost.conf file and look for the existing location / and extend it, so it looks like this;

location / {
    proxy_cache ghost_cache;
    proxy_cache_valid 60m;
    proxy_cache_valid 404 1m;
    proxy_ignore_headers Set-Cookie;
#   proxy_cache_bypass $http_cache_control; # uncomment this to enable cache bypass
    proxy_hide_header Set-Cookie;
    proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
    proxy_ignore_headers Cache-Control;
    add_header X-Cache-Status $upstream_cache_status;

    proxy_set_header Host $http_host;
    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 $scheme;
    proxy_pass http://ghost; # this is the previously defined upstream

This configuration tells Nginx to use the cache. The proxy_cache_valid sets a default cache time of 60m on valid response of HTTP status 200, 301 or 302 and for 404 responses for 1m.

We have to avoid caching the admin part, we need that live in order to work correctly. So we have to add the following:

location ^~ /ghost/ {
    proxy_set_header Host $http_host;
    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 $scheme;
    proxy_pass http://ghost;

That's it, now we have everything in place.

Google's advice on enabling leverage browser caching.