Configuring nginx to speed up Ghost blog powered by Docker

I was searching for some nginx configurations and found a blog post to speed up a Ghost blog. Unfortunately it doesn't work out of the box. However it was very interesting to set up nginx as a reverse proxy and cache for my Node.js Ghost blog powered by Docker.

nginx configuration

The nginx configuration is more complex. I want to serve static content directly by nginx and cache the blog sites except the admin area. One negative point is, that the nginx location config contains the theme path, so you cannot switch between themes without changing the nginx config. It doesn't matter to me, because I only use Casperion.

The nginx configuration looks like this.

# cache config
proxy_cache_path /cache levels=1:2 keys_zone=ghostcache:100m inactive=24h;
proxy_cache_key "$scheme$request_method$host$request_uri";

server {
    listen 80;
    root /var/www/ghost;
    server_name blog.sandro-keil.de;
    
    charset utf-8;
    
    # deliver images directly
    location ~* /content/images {
        expires 1M;
        access_log off;
        add_header Cache-Control "public";
    }
    # deliver assets directly
    location ~* /assets {
        root /var/www/ghost/content/themes/casperion/assets;
        expires 1M;
        access_log off;
        add_header Cache-Control "public";
    }
    # no admin caching
    location ~* /ghost/ {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $http_host;
        proxy_pass http://ghost:2368;
    }
    # no caching of ghost core files
    location ~* /(shared|scripts|public) {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $http_host;
        proxy_pass http://ghost:2368;
    }
    # favicon
    location = /favicon.ico {
        root /var/www/ghost/content/themes/casperion/assets;
        access_log off;
        log_not_found off;
        expires 30d;
    }
    # cache urls
    location ~ / {
        proxy_cache ghostcache;
        proxy_cache_valid 200 60m;
        proxy_cache_bypass  $http_cache_control;
        add_header X-Proxy-Cache $upstream_cache_status;
        proxy_ignore_headers X-Accel-Expires Expires Cache-Control;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $http_host;
        proxy_pass http://ghost:2368;
    }
}

If you check the headers of your request you should see a header entry with X-Proxy-Cache: HIT if the cache was used. Note that you must change the paths and server name.

fig.yml

The easiest way to link 2 container is done via fig. The configuration is simple.

nginx:
  image: nginx
  ports:
    - 80:80
  volumes:
    - /data/ghost:/var/www/ghost:ro
    - /data/nginx/config:/etc/nginx:ro
  links:
    - ghost

ghost:
  image: dockerfile/ghost
  ports:
    - 2368:2368
  volumes:
    - /data/ghost:/ghost-override

Well, I have to stop and to remove the current running Ghost container and then run fig up -d, otherwise the linking with existing container doesn't work correctly. However now it runs great.

By the way, the nginx and Node.js Ghost container runs on a 1 ghz/1 gb ram machine without any problems.

Container monitoring with Upstart

To ensure that the docker container are always running, we need something to watch them. This is easy with Upstart. Upstart restarts the docker container if they fail (usually due to unhandled errors or configuration issues) and ensures the (re)start on system boot. Create the following file /etc/init/figcontainer.conf.

description "fig service runner"
start on filesystem and started docker
stop on runlevel [!2345]
respawn
chdir /data
script
    exec /usr/local/bin/fig start
end script

Now you can start the container with sudo initctl start figcontainer or stop the container with sudo initctl stop figcontainer. If you stop a container with the docker stop command, Upstart will immediately restart fig and fig will restart all containers.

Resources

Article picture: Starfield 1a by jagged-eye under CC BY-NC-SA 2.0