Caching Ghost with Apache for Maximum Performance, 100x faster
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 mod_disk_cache
makes easy work of this.
Configuring the cache:
First we need to enable mod_cache
, mod_cache_disk
and mod_expires
:
sudo a2enmod cache
sudo a2enmod cache_disk
sudo a2enmod expires
Then edit your virtual host file, usually /etc/apache2/sites-enabled/default.conf
(may differ based on setup)
<VirtualHost *:80>
# 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
<Location />
# 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 "access plus 15 minutes"
</Location>
# 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.
<Location /ghost>
# Don't cache the ghost admin interface
SetEnv no-cache
</Location>
</VirtualHost>
Finally we need to restart apache and then we are done!
sudo service apache2 restart
Now it's time to check whether your cache is working by inspecting the headers.
:~$ 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
...
As long as you see an X-Cache
and a Cache-Control
header it is all working. Now lets see what kind of performance improvement we have achieved.
Performance Testing:
To quantify the improvement, I broke out ApacheBench
and did a couple of quick tests from a neighboring machine.
First test without caching enabled, yielding approximately 25 Requests per second with a median response time of ~4 seconds!:
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)
After enabling the caching, we get ~2700 Requests per second with a median response time of 31 milliseconds!. That is 100x more requests served per second!
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)