Building & Deploying a Ghost Blog with Nanobox

Ghost is an awesome project. For me, its simplicity and laser-focus on content publishing has made it my go-to platform when a project requires an easy way for users to publish content.

This article walks through building a Ghost blog from scratch with nothing installed other than Nanobox, then deploying that blog to a live environment.

If you don't have it installed already, go ahead and create a Nanobox account (it's free) and download Nanobox (it's also free).

Ghost Quickstart

The Ghost Quickstart is preconfigured with everything discussed in this article. If you're just looking to get a Ghost blog up and running quickly, feel free to use the quickstart, then jump down to the "Deploy to Production" section of this article.

Create a New Project Directory

Create a new directory for your Ghost project and cd into it. The name of the directory is completely up to you, but for the purposes of this tutorial, I'm going to use ghost-project.

# create a new project directory
mkdir ghost-project

# cd into the new project directory
cd ghost-project  

Add a boxfile.yml

Nanobox uses the boxfile.yml to build and prepare your app's environment. Ghost is a Node.js project, so we'll want to use Nanobox's Node.js engine, which will provide the necessary Node.js runtime. Ghost also requires at least Node.js v6.9.

In the root of your project, create a file named boxfile.yml with the following:

Basic boxfile.yml
run.config:  
  engine: nodejs
  engine.config:
    runtime: nodejs-6.9

Install Ghost

Using the boxfile.yml in your project, Nanobox will automatically create a local, virtual Node.js development environment. Run the following from the root of your project:

nanobox run  

This will create a virtual environment on your local machine, install Node.js and its dependencies, then drop you into an interactive console inside the virtual environment.

Use Yarn to Create a New Node.js Project

Yarn is a drop-in replacement for npm and is quickly becoming the dependency manager of choice for Node.js projects. For this tutorial, we'll use yarn.

yarn init  

This will initiate a new Node.js project by creating a package.json in the working directory and walk through some interactive prompts gathering information about the project. This information is stored in your package.json which is also be used to define your project's dependencies.

Add & Install Ghost as a Node Module

I recommend installing Ghost as a Node module rather than simply downloading the Ghost source code and using that for the project. Ghost, when loaded as a module, is much easier to keep up to date (yarn upgrade will download and install the newest Ghost version). There are a few things you'll need to add to get Ghost running as a module, but we'll cover these next.

Use yarn to add the current stable version of Ghost (v0.11.7 at the time of writing this article).

yarn add ghost@0.11.7  

Configure Ghost

Ghost gets installed with a config.example.js that can be used as a template for configuring Ghost. Ghost also comes with a pre-populated content directory that includes the default "Casper" theme as well as other necessary directories. Since we installed Ghost as a Node module, we need to copy the config.example.js and the content directory inside node_modules to the root of your project.

# copy node_modules/config.example.js to config.js
cp node_modules/ghost/config.example.js config.js

# copy node_modules/content directory to content
cp -a node_modules/ghost/content content  

Create an app.js

Since Ghost is going to run out of the node_modules directory, we need to tell it to use the config.js in the root of the project rather than in the module. Create a file named app.js in the root of your project with the following:

app.js
var path = require('path');  
var ghost = require('ghost');  
ghost({  
  // Tell node to use the config.js in your project root
  // rather the the config.js in the module
  config: path.join(__dirname, 'config.js')
}).then(function (ghostServer) {
  ghostServer.start();
})

Update the config.js

Ghost pulls its configuration from the config.js in the root of your project. There are a few updates you'll need to make to get Ghost running properly within the Nanobox context.

Update the Server Host to 0.0.0.0

By default, Ghost listens on 127.0.0.1, but Nanobox requires apps to listen on 0.0.0.0. Update the server config in both the production and development sections of your config.js to the to listen on 0.0.0.0.

production: {  
    // ...
    server: {
        host: '0.0.0.0',
        port: '2368'
    }
}
development: {  
    // ...
    server: {
        host: '0.0.0.0',
        port: '2368'
    }
}

Update the Content Path

Ghost uses the paths config to determine where themes, images, apps, and possibly data are stored. Since Ghost is loaded as a module, by default, it will try to find these things in the node_modules directory. We need to update the config.js to point Ghost to the content directory in the project rather than the module.

Add the following to both the production and development sections of your config.js:

production: {  
    // ...
    paths: {
        contentPath: '/app/content/'
    }
}
development: {  
    // ...
    paths: {
        contentPath: '/app/content/'
    }
}

App URL

Ghost uses the url setting in the config.js to build links for your site. Update the url setting in the production section of your config.js to be whatever domain you're going to use in production.

production: {  
    url: 'http://yourdomain.com',
    // ...
}

Nanobox allows you to easily add and use DNS aliases when working locally. For the purposes of this tutorial, I'll use ghost.dev, but you can use whatever you'd like. This domain will be used later. Update the url in the development section of your config.js to the following:

development: {  
    url: 'http://ghost.dev:2368',
    // ...
}

Be sure to include the port.

Configure Mail

Allowing Ghost to send mail while in development is optional, but in production, email is used to add new team members to the app. Be sure to configure the mail settings in your config.js with the credentials provided by your SMTP provider.

Add & Configure Your Database

You have some options when it comes to what database to use with Ghost. By default, Ghost uses SQLite, but I prefer to use Postgres.

Add a PostgreSQL to Your boxfile.yml

Nanobox automatically creates application components, such as a database or web server, included in your boxfile.yml. To include a Postgres database in your app, add the following to your boxfile.yml.

data.db:  
  image: nanobox/postgresql:9.4

Add the 'pg' Node Module

In order for Ghost to communicate with Postgres, you need to include the pg node module in your project. From inside your Nanobox console, run:

yarn add pg  

Update Your Database Connection

Nanobox automatically generates your database's connection credentials as well as environment variables for each. Update the database config in both the production and development sections of your config.js with the following:

production: {  
    // ...
    database: {
        client: 'pg',
        connection: {
          host: process.env.DATA_DB_HOST,
          user: process.env.DATA_DB_USER,
          password: process.env.DATA_DB_PASS,
          database: 'gonano',
          charset: 'utf8'
        },
        debug: false
    },
    // ...
}
development: {  
    // ...
    database: {
        client: 'pg',
        connection: {
          host: process.env.DATA_DB_HOST,
          user: process.env.DATA_DB_USER,
          password: process.env.DATA_DB_PASS,
          database: 'gonano',
          charset: 'utf8'
        },
        debug: false
    },
    // ...
}

Exit Out of the Nanobox Console

For the sake of context-clarity, go ahead and exit out of your Nanobox console back to your OS's native console before continuing.

exit  

Run the App Locally

Ok, now we're ready to run Ghost locally using Nanobox. We'll first add a DNS alias which can be used to easily access the Ghost app from a browser (Be sure to use the development url you added earlier). Then we'll use Nanobox to run Ghost with the node app.js command.

# add a convenient way to access the app from the browser
nanobox dns add local ghost.dev

# start nanobox and run Ghost
nanobox run node app.js  

Nanobox will spin up the virtualized local development environment, load all your app's dependencies, detect/provision/configure your Postgres database, then start Ghost using the development configuration.

You'll be able to access the app at ghost.dev:2368
(or whatever domain you've configured for development)

Your local codebase is mounted into your virtual development environment, so as you make changes to the code, they'll be reflected in the running app.

Prepare for Production

With Ghost running locally, you're ready to put the final touches on it before using Nanobox to deploy it to a live infrastructure.

Configure an Nginx Proxy

It's generally recommended to run Ghost behind some type of proxy rather than connecting it directly to the public network. Nginx is a powerful, trusted, open-source web server that makes for a great proxy. To include the nginx package in your project, add the following to the run.config section of your boxfile.yml:

run.config:  
  # ...
  extra_packages:
    - nginx

In the root of your project, create a new config directory and add an nginx.conf with the following:

config/nginx.conf
worker_processes 1;  
daemon off;

events {  
    worker_connections 1024;
}

http {  
    include /data/etc/nginx/mime.types;
    sendfile on;

    gzip              on;
    gzip_http_version 1.0;
    gzip_proxied      any;
    gzip_min_length   500;
    gzip_disable      "MSIE [1-6]\.";
    gzip_types        text/plain text/xml text/css
                      text/comma-separated-values
                      text/javascript
                      application/x-javascript
                      application/atom+xml;

    # Proxy upstream to ghost
    upstream ghost {
        server 127.0.0.1:2368;
    }

    # Configuration for Nginx
    server {

        # Listen on port 8080
        listen 8080;

        root /app;

        try_files $uri/index.html $uri @ghost;

        # Proxy connections to ghost
        location @ghost {
            proxy_pass         http://ghost;
            proxy_redirect     off;
            proxy_set_header   Host $host;
        }
    }
}

This nginx.conf will be used to start the Nginx proxy in production.

Add Persistent Shared Storage

Ghost allows you to upload images into a production app, requiring content/images to be writable. In order for written content to persist between deploys, you need to add a persistent storage service that 1) will persist between deploys and 2) will act as a shared writable filesystem when running Ghost in a multi-node web cluster.

Nanobox makes this easy. Add the following to your boxfile.yml:

data.storage:  
  image: nanobox/unfs:0.9

This storage component will act as a persistent, shared, writable filesystem. Anything written to it will persist between deploys and be shared between nodes in a multi-node cluster. Configuring your app to write to this component is done in your web component config.

Add a Web Component

Web components provide publicly accessible web server(s) for your app in production. Add the following to your boxfile.yml:

web.main:  
  start:
    nginx: nginx -c config/nginx.conf
    ghost: node app.js --production
  network_dirs:
    data.storage:
      - content/images

This configuration will:

  1. Create a publicly accessible web server in production
  2. Start Nginx using the config/nginx.conf file
  3. Start Ghost in production-mode
  4. Mount content/images into the persistent storage service. More information is available in the Network Storage documentation.

The Final boxfile.yml

If you've followed this tutorial step-by-step up to this point, your boxfile.yml should look something like this:

run.config:  
  engine: nodejs
  engine.config:
    runtime: nodejs-6.9
  extra_packages:
    - nginx

web.main:  
  start:
    nginx: nginx -c /app/config/nginx.conf
    ghost: node app.js --production
  network_dirs:
    data.storage:
      - content/images

data.db:  
  image: nanobox/postgresql:9.4

data.storage:  
  image: nanobox/unfs:0.9

Deploy to Production

Ok, you're ready to deploy your Ghost app to live servers using Nanobox.

Create a New App

Go to your Nanobox dashboard and launch a new app. If you haven't already, you will need to configure a provider. Nanobox will deploy your app to your cloud provider of choice.

Add the App as a Remote

Once the app is created, use your app-name and the following command to add it as a remote to your local project:

nanobox remote add app-name  

Deploy

With a live remote ready, go ahead and deploy:

nanobox deploy  

Nanobox will package up your app's code and runtime, upload it to your cloud provider, then provision and start your app in your production environment on live servers.

Further Steps

With your app in production, there are a few things you might want to do next. The following links to Nanobox documentation will help.

Scott Anderson

Designer, code-dabbler, writer, foodie, husband, and father. Core Team Member at Nanobox.

Subscribe to Nanobox

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!