I wrote this entry when I set up another blog using Ghost. Perhaps someone might find this useful. I certainly might if I ever need to recall the steps.

For those who don’t want to set up Ghost themselves, there is (at the time of writing) a hosted option at 29$ a month, but I thought I’d set it up myself and get a feel for the platform. I’m not expecting any significant traffic, so I’m opting for a minimal configuration with a micro instance on Google Compute and Cloud SQL running on traditional HDD:s.

Let’s see how to set it up.

At the time of writing, Ghost supports node versions >=6.9 <7.*, making 6.9.5 the latest usable / recommended version.

Step one, get the node binary and move it to /usr/local.

wget https://nodejs.org/download/release/v6.9.5/node-v6.9.5-linux-x64.tar.gz
tar -C /usr/local --strip-components 1 -zxvf node-v6.9.5-linux-x64.tar.gz

Get Ghost.

mkdir /srv/node/ghost
cd /srv/node/ghost
wget https://github.com/TryGhost/Ghost/releases/download/1.6.1/Ghost-1.6.1.zip
unzip Ghost-1.6.1.zip
rm Ghost-1.6.1.zip

Install Ghost’s dependencies

npm install --production

Copy Ghost’s example config file to the root dir and edit host, user, password and database to match the SQL servers configuration. Also add a `url` field to set the public url of the site so it doesn’t default to localhost.

cp core/server/config/env/config.production.json .
vi config.production.json

Create database tables for the production environment.

NODE_ENV=production knex-migrator init

I’m going to use PM2 to start Ghost, so I’m creating a pm2 user to own the files.

adduser pm2 --gecos "Node Process Manager"
chown -R pm2:pm2 .

To start Ghost in production mode using PM2, set the environment variable NODE_ENV to production using a PM2 ecosystem file.

touch ecosystem.config.js
vi ecosystem.config.js

I’m using the following config, currently with production as the default and only option.

module.exports = {
    apps: [{
        name: "ghost",
        script: "/srv/node/ghost/index.js",
        watch: false,
        env: {
            "NODE_ENV": "production",

Run the blog and save pm2:s process list.

pm2 start ecosystem.config.js
pm2 save

Enable PM2 to start on boot by generating a systemd int script and starting and enabling the service.

pm2 startup systemd
<run the displayed command>

At this point Ghost is running but isn’t reachable from the outside. I’m going to set up NGINX as a reverse proxy. Http traffic is already enabled via Google Compute’s firewall.

Install NGINX and copy the example config file to a new file, to be used as the config file for the blog.

apt-get install nginx
cd /etc/nginx/sites-available/
cp default ghost

Edit the file to point to the address where Ghost is running (proxy_pass http://<host>:<port>;). Then link or copy the file to ../sites-enabled/, delete the default file which serves the static NGINX welcome page and reload the NGINX config.

cp ghost ../sites-enabled/
rm ../sites-enabled/default
service nginx reload

Seems to work. Overall pretty straightforward and the micro instance seems fast enough for the time being.