<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[ghost - Matthias Lee - Musings on Software and Performance Engineering]]></title><description><![CDATA[Matthias Lee is a Software Performance Engineer, Technical Lead and Computer Science PhD. Currently a Principal Performance Engineer at Appian.]]></description><link>https://matthiaslee.com/</link><image><url>https://matthiaslee.com/favicon.png</url><title>ghost - Matthias Lee - Musings on Software and Performance Engineering</title><link>https://matthiaslee.com/</link></image><generator>Ghost 2.14</generator><lastBuildDate>Sat, 06 Dec 2025 12:52:16 GMT</lastBuildDate><atom:link href="https://matthiaslee.com/tag/ghost-tag/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Caching Ghost with Apache for Maximum Performance, 100x faster]]></title><description><![CDATA[<p>Ghost can be a bit CPU hungry, especially for a lightweight (single core) VPS, but all of that can me negated with a little bit of caching. Luckily Apache's <code>mod_disk_cache</code> makes easy work of this.</p>
<h2 id="configuringthecache">Configuring the cache:</h2>
<p>First we need to enable <code>mod_cache</code>, <code>mod_cache_disk</code></p>]]></description><link>https://matthiaslee.com/caching-ghost-with-apache-for-maximum-performance-100x-faster/</link><guid isPermaLink="false">5a0a60d882e47c00018dabf0</guid><category><![CDATA[apache]]></category><category><![CDATA[cache]]></category><category><![CDATA[ghost]]></category><category><![CDATA[performance testing]]></category><dc:creator><![CDATA[Matthias A. Lee]]></dc:creator><pubDate>Sun, 23 Apr 2017 05:35:44 GMT</pubDate><content:encoded><![CDATA[<p>Ghost can be a bit CPU hungry, especially for a lightweight (single core) VPS, but all of that can me negated with a little bit of caching. Luckily Apache's <code>mod_disk_cache</code> makes easy work of this.</p>
<h2 id="configuringthecache">Configuring the cache:</h2>
<p>First we need to enable <code>mod_cache</code>, <code>mod_cache_disk</code> and <code>mod_expires</code>:</p>
<pre><code>sudo a2enmod cache
sudo a2enmod cache_disk
sudo a2enmod expires
</code></pre>
<p>Then edit your virtual host file, usually <code>/etc/apache2/sites-enabled/default.conf</code> (may differ based on setup)</p>
<pre><code>&lt;VirtualHost *:80&gt;
     # Domain name and Alias
     ServerName example.com
     ServerAlias www.example.com

     # Configure Reverse proxy for Ghost
     ProxyPreserveHost on
     ProxyPass / http://localhost:1234/
     ProxyPassReverse / http://localhost:1234/

     CacheQuickHandler off
     CacheLock on
     CacheLockPath /tmp/mod_cache-lock
     CacheLockMaxAge 5
     CacheIgnoreHeaders Set-Cookie

     &lt;Location /&gt;
        # Enable disk cache, set defaults
        CacheEnable disk
        CacheHeader on
        CacheDefaultExpire 600
        CacheMaxExpire 86400
        FileETag All

        # Set cache-control headers for all request
        # which do not have them by default
        # must enable: mod_expires
        ExpiresActive on
        ExpiresDefault &quot;access plus 15 minutes&quot;
    &lt;/Location&gt;

    # While this is not needed since Ghost automatically
    # passes back 'Cache-Control: no-cache, private'
    # It makes me feel better to explicitly state it again.
    &lt;Location /ghost&gt;
        # Don't cache the ghost admin interface
        SetEnv no-cache
    &lt;/Location&gt;

&lt;/VirtualHost&gt;
</code></pre>
<p>Finally we need to restart apache and then we are done!</p>
<pre><code>sudo service apache2 restart
</code></pre>
<p>Now it's time to check whether your cache is working by inspecting the headers.</p>
<pre><code>:~$ curl -i -X GET http://example.com | less
HTTP/1.1 200 OK
Date: Sun, 21 Apr 2017 05:15:13 GMT
Server: Apache
Cache-Control: public, max-age=0, max-age=900
Expires: Sun, 21 Apr 2017 05:30:12 GMT
Age: 832
X-Cache: HIT from example.com
...
</code></pre>
<p>As long as you see an <code>X-Cache</code> and a <code>Cache-Control</code> header it is all working. Now lets see what kind of performance improvement we have achieved.</p>
<h1 id="performancetesting">Performance Testing:</h1>
<p>To quantify the improvement, I broke out <code>ApacheBench</code> and did a couple of quick tests from a neighboring machine.<br>
First test without caching enabled, yielding approximately <strong>25 Requests per second</strong> with a median response time of <strong>~4 seconds!</strong>:</p>
<pre><code>Concurrency Level:      100
Time taken for tests:   40.943 seconds
Complete requests:      1000
Requests per second:    24.42 [#/sec] (mean)
Time per request:       4094.286 [ms] (mean)
Time per request:       40.943 [ms] (mean, across all concurrent requests)
Transfer rate:          282.64 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   1.7      1      14
Processing:  1052 3936 670.4   3933    5252
Waiting:     1052 3936 670.4   3933    5252
Total:       1056 3938 669.7   3934    5252

Percentage of the requests served within a certain time (ms)
  50%   3934
  66%   4119
  75%   4261
  80%   4406
  90%   4554
  95%   5067
  98%   5173
  99%   5211
 100%   5252 (longest request)

</code></pre>
<p>After enabling the caching, we get <strong>~2700 Requests per second</strong> with a median response time of <strong>31 milliseconds!</strong>. That is 100x more requests served per second!</p>
<pre><code>Concurrency Level:      100
Time taken for tests:   18.487 seconds
Complete requests:      50000
Failed requests:        0
Total transferred:      597400000 bytes
HTML transferred:       578850000 bytes
Requests per second:    2704.57 [#/sec] (mean)
Time per request:       36.974 [ms] (mean)
Time per request:       0.370 [ms] (mean, across all concurrent requests)
Transfer rate:          31556.82 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    8  52.1      4    1019
Processing:     1   29  19.1     26     693
Waiting:        1   28  16.9     26     659
Total:          2   37  55.1     31    1158

Percentage of the requests served within a certain time (ms)
  50%     31
  66%     34
  75%     37
  80%     40
  90%     46
  95%     51
  98%     67
  99%     91
 100%   1158 (longest request)
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Migration finally done.]]></title><description><![CDATA[<p>As of late last week I have finally completed the migration away from the previous incarnation of my Drupal-based blog. Even since its initial deployment I found it to be overly complicated for me to get simple things accomplished. I would often think about writing a post but usually got</p>]]></description><link>https://matthiaslee.com/migration-finally-done/</link><guid isPermaLink="false">5a0a60d882e47c00018dabef</guid><category><![CDATA[ghost]]></category><category><![CDATA[drupal]]></category><category><![CDATA[personal]]></category><dc:creator><![CDATA[Matthias A. Lee]]></dc:creator><pubDate>Thu, 20 Apr 2017 03:41:00 GMT</pubDate><content:encoded><![CDATA[<p>As of late last week I have finally completed the migration away from the previous incarnation of my Drupal-based blog. Even since its initial deployment I found it to be overly complicated for me to get simple things accomplished. I would often think about writing a post but usually got hung up on actually properly formatting and writing the post. In the meantime I started messing around with Ghost, first as an quick and easy-to-use blog separate from my main website, then even ended up using it for our wedding website last year.</p>
<p>After sifting through many different themes I think I've arrived at one which simple, clean and un-obtrusive. I have completed the content migration and ultimately ended up merging my main website and my blog together into one easily manageable platform. Along the way I did some performance tuning using <code>ApacheBench</code> to see how Ghost does under load and ultimately enabled Apache's <code>mod_cache_disk</code> to prevent node.js from pegging the CPU on my humble VPS.</p>
<p>I look forward to having a clean and easy to use platform at my disposal to document some of my thoughts, tips and tricks in a way that it may be useful to others.</p>
]]></content:encoded></item></channel></rss>