I was recently introduced to Ghost, a new free and open source blogging platform. I was visiting jsDelivr and reading up on their founder, Dmitriy Akulov, and his amazing blog. I saw he was using Ghost and thought I would give it a shot.

What led me to use Ghost?

I have long been a huge fan (and, still am!) of WordPress, having worked with it since Thelonious, simply known as version 3.0. In recent years WordPress has grown significantly but with one caveat - it seems to be moving away from individuals who only want a simple way to blog. In the long run, that has allowed WordPress to do some amazing things. Since I used to work for one of the largest Managed WordPress hosts, WP Engine, I was able to see a plethora of sites of which you would never guess were run on WordPress. WordPress is built for a wide variety of individuals, but, at least for now I am starting to believe that Ghost may be for me.

I was impressed with the simplicity of Ghost. I enjoy writing in Markdown, so much so I write all my Evernote notes in Markdown using an application called Marxico. I also was frustrated how hard it was to find a minimalist theme that I enjoyed on WordPress. I kept defaulting back to twentyfifteen or twentysixteen for themes. Even though I don't mind those themes, I wanted something simpler and with more speed.


Speed


I love speed. Speed is king on the internet and if your sites are loading slow, good luck trying to stay ahead - you're penalized by the mindset of individuals online today that it must load NOW and even worse, you're penalized online by search engines for a slow loading website.

So, let's get Ghost even faster than it is. As a benchmark here is what the system is running:

I am running a 2GB RAM Ubuntu 14.04 droplet at Digital Ocean.

root@web01:/# uname -r
3.13.0-86-generic
             total       used       free     shared    buffers     cached
Mem:          2001       1551        449          4         91       1060
-/+ buffers/cache:        400       1601
Swap:            0          0          0
root@web01:~# nginx -V
nginx version: nginx/1.4.6 (Ubuntu)
built by gcc 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.3)
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_addition_module --with-http_dav_module --with-http_geoip_module --with-http_gzip_static_module --with-http_image_filter_module --with-http_spdy_module --with-http_sub_module --with-http_xslt_module --with-mail --with-mail_ssl_module
root@web01:~#

Zone Creation at MaxCDN


  1. Create zone in the MaxCDN Portal

  2. Modify the zone configuration to match the below:

MaxCDNZone

  1. You can create a CNAME record for the relevant custom record pointing to your CNAME as provided in the MaxCDN portal.

  2. Verify that your DNS has propagated. You can do this either via dig cname $customurlhere or Google Toolbox.

Example output below:

Jacobs-MacBook-Pro:~ jacobwall$ dig cname blog.himynameisjacob.com

; <<>> DiG 9.8.3-P1 <<>> cname blog.himynameisjacob.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41011
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;blog.himynameisjacob.com.     	IN     	CNAME

;; ANSWER SECTION:
blog.himynameisjacob.com. 210  	IN     	CNAME  	himynameisjacob.jacobwall.netdna-cdn.com.

;; Query time: 23 msec
;; SERVER: 192.168.10.139#53(192.168.10.139)
;; WHEN: Mon Aug 29 13:10:00 2016
;; MSG SIZE  rcvd: 93

Jacobs-MacBook-Pro:~ jacobwall$

Nginx Configuration for using MaxCDN w/ Ghost


  1. Modify /etc/nginx/sites-enabled/ghost

Before

server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

    server_name my-ghost-blog.com; # Replace with your domain

    root /usr/share/nginx/html;
    index index.html index.htm;

    client_max_body_size 10G;

    location / {
        proxy_pass http://localhost:2368;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_buffering off;
    }
}

After

server {
    listen 80;
    server_name zone.username.netdna.com;

    location /ghost {
        proxy_hide_header Vary;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $http_host;
        proxy_pass http://127.0.0.1:2368;
    }

    location / {
        proxy_hide_header Vary;
        proxy_hide_header Cache-Control;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $http_host;
        proxy_pass http://127.0.0.1:2368;
    }
}
  1. Restart nginx with sudo /etc/init.d/nginx restart

Successful Output Below:

root@web01:/# sudo /etc/init.d/nginx restart
[ ok ] Restarting nginx (via systemctl): nginx.service.
  1. Verify that your domain is serving traffic successfully over MaxCDN. In this example. I will use ApacheBench and then via curl.

ApacheBench Syntax:

ab -H 'Host: youractualurl.com' http://zone.username.netdna.com/assets/css/screen.css

You can also replace zone.username.netdna.com with your custom URL if you created the CNAME at your DNS provider.

Jacobs-MacBook-Pro:~ jacobwall$ ab -H 'Host: himynameisjacob.com' http://blog.himynameisjacob.com/assets/css/screen.css
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking blog.himynameisjacob.com (be patient).....done


Server Software:        NetDNA-cache/2.2
Server Hostname:        blog.himynameisjacob.com
Server Port:            80

Document Path:          /assets/css/screen.css
Document Length:        162 bytes

Concurrency Level:      1
Time taken for tests:   0.092 seconds
Complete requests:      1
Failed requests:        0
Non-2xx responses:      1
Total transferred:      316 bytes
HTML transferred:       162 bytes
Requests per second:    10.81 [#/sec] (mean)
Time per request:       92.478 [ms] (mean)
Time per request:       92.478 [ms] (mean, across all concurrent requests)
Transfer rate:          3.34 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       34   34   0.0     34      34
Processing:    58   58   0.0     58      58
Waiting:       56   56   0.0     56      56
Total:         92   92   0.0     92      92
Jacobs-MacBook-Pro:~ jacobwall$

curl Syntax

curl -IH 'Host: yourdomain.com' http://zone.username.netdna.com/assets/css/screen.css
Jacobs-MacBook-Pro:~ jacobwall$ curl -IH 'Host: blog.himynameisjacob.com' https://himynameisjacob-jacobwall.netdna-ssl.com/assets/css/screen.css
HTTP/1.1 200 OK
Date: Mon, 29 Aug 2016 18:43:04 GMT
Content-Type: text/css; charset=UTF-8
Content-Length: 46105
Connection: keep-alive
X-Powered-By: Express
Cache-Control: public, max-age=31536000
Last-Modified: Mon, 29 Aug 2016 15:34:09 GMT
ETag: W/"b419-156d6efb735"
Vary: Accept-Encoding
Server: NetDNA-cache/2.2
X-Cache: HIT
Accept-Ranges: bytes

Jacobs-MacBook-Pro:~ jacobwall$

You're now setup with MaxCDN!

Now, how does this actual effect our performance with Ghost?

With No CDN

After MaxCDN

Yes, you read that right... a 2GB RAM droplet running Ghost was able to maintain a client load of 10,000 requests per second. In 60 seconds Ghost + MaxCDN were able to deliver 1,383,319 views encapsulating 50.80 GB of transfer without a single hiccup.

I did not get a chance to capture a picture of when the RPS was at peak, but, from a previous test here is what pure cached awesomeness looks like.

RPS


Key Takeaways:


  • Nginx is powerful; that is why we use it at MaxCDN. We have an excellent blog post here that may be of interest on why we use nginx.

  • Choose a blogging platform/CMS that fits your needs. If you don't need all the bells & whistles, then Ghost may be a good fit.

  • Use a CDN, no matter if you are using Ghost or not. For the performance increase, the cost of delivering bandwidth over a CDN versus the reduction of processing power (and, bandwidth still) at the origin is worth it.