In a word, nuanced

While Ubuntu is one of the easiest linux variants to pickup and use, node.js certainly becomes an exception. Not because there’s anything inherently more difficult in using this combination, but there are subtle changes that occur when using the combinations of different versions of Ubuntu (also Debian) and node.js.

Ubuntu convienently has already added the node.js packages to the apt-get sources (apt-get install node, apt-get install nodejs, and apt-get install npm), so installing and managing these packages’ upgrades isn’t an issue. Getting the Ghost files onto the server isn’t an issue for anyone familiar with FTP or cURL either.

I ran into trouble (and I suspect many others have as well) when using newer versions of node.js than the Ghost package dependencies required. Strangely, the location of node changed both names and location in a newer version than what the sqlite3 dependency was expecting, so a symlink was needed in order to install this package.(1)

Moving past the dependency issues, the second task is to ensure that node continually runs so that the Ghost-powered blog remains online. Ubuntu has has upstart installed by default, which largely replaces System V and removes the need for writing an init script. This is quickly achieved by creating the file /etc/init/ghost.conf which contains:

start on startup
    cd /PATH/TO/ghost
    npm start
end script

and will start Ghost on system boot or with the start ghost command, removing the limitation of having an active shell running npm start for Ghost.(2, 3)

The last interesting bit about Ghost is that it runs on a node.js server. While this server can and does listen for incoming connections to the external IP, it’s very minimal and isn’ t configured for logging, caching, or any other advanced server functionality. I’d recommend having it listen on localhost and proxy the node.js server with another, more robust server such as Nginx, which is covered in the Ghost documentation.


By default, Ghost’s server employs static content caching with a TTL set to one year and for all other assets, adds the following Cache-Control header: Cache-Control: public, max-age=0. I don’t fully understand the purpose of this configuration, as it tells downstream caches that they may cache the resource for a total of zero seconds. I find this does more harm than good- particularly when conducting optimization tests (which likely will throw a warning in this instance for having a low TTL on a cacheable resource). If the intent was to not cache the resource, a cache control header containing any of the following would be more beneficial: no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0.

To alter this header, open /path/to/ghost/core/server/middleware/middleware.js and edit the following code segment:

//### CacheControl Middleware
// provide sensible cache control headers
cacheControl: function (options) {
    /*jslint unparam:true*/
    var profiles = {
            'public': 'public, max-age=0',
            'private': 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0'

so that the 'public': 'public, max-age=0' line reads differently or is commented out.

As an aside, since the ghost documentation advises proxying with nginx, it would be nice to have an option to disable the caching module entirely as controling response headers in the nginx configuration files is much easier and more customizeable.