I just moved my personal blog from Jekyll on Heroku to Ghost on Digital Ocean. Although Digital Ocean provides a 1-click application image for Ghost, I decided that I wanted to install Ghost myself, so I can have more control over the instance and application.

Node version

After creating a droplet with CentOS 7, the first to install ins Node.js. Recommended Node for Ghost is >0.10.40. So I used nvm to install this Node version.

When installing nvm, it's a good idea to specify the NVM_DIR and point to a shared path. By default, nvm is installed to current user's home directory, which could be root user's home directory. This can cause file permission issues when Ghost is started using another user.

curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.0/install.sh | NVM_DIR="/var/nvm" bash  

Then use nvm install 0.10.43 to install Node. Now we can use which node to find the actual path of Node binary.

Service script

To make sure Ghost is started after system restarts, we need to add a service script. Create /etc/init.d/ghost file with following content. The script is based on what I found in this article.

The most important part in this script is the command to start Ghost: /var/nvm/v0.10.43/bin/node index.js >> /var/log/ghost/ghost.log &. Here I used the Node binary installed by nvm to start Ghost. I also used user ghost to run Ghost.

Use chkconfig --add ghost to have the script run at startup. Use service ghost start to start Ghost, service ghost stop to Stop Ghost.

#!/bin/sh
#
# ghost - this script starts the ghost blogging package
#
# chkconfig:   - 95 20
# description: ghost is a blogging platform built using javascript \
#              and running on nodejs
#

# Source function library.
. /etc/rc.d/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

# Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 0

exec="/var/nvm/v0.10.43/bin/node index.js >> /var/log/ghost/ghost.log &"  
prog="ghost"

[ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog

lockfile=/var/lock/subsys/$prog

start() {  
    #[ -x $exec ] || exit 5
    echo -n $"Starting $prog: "
    # if not running, start it up here, usually something like "daemon $exec"
    export NODE_ENV=production
    cd /var/data/ghost/
    daemon --user=ghost $exec
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}

stop() {  
    echo -n $"Stopping $prog: "
    # stop it here, often "killproc $prog"
    pid=`ps -u $prog -fw | grep $prog | grep -v " grep " | awk '{print $2}'`
    kill -9 $pid > /dev/null 2>&1 && echo_success || echo_failure
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}

restart() {  
    stop
    start
}

my_status() {  
        local base pid lock_file=

        base=${1##*/}

        # get pid
        pid=`ps -u $prog -fw | grep $prog | grep -v " grep " | awk '{print $2}'`

        if [ -z "${lock_file}" ]; then
        lock_file=${base}
        fi
        # See if we have no PID and /var/lock/subsys/${lock_file} exists
        if [[ -z "$pid" && -f /var/lock/subsys/${lock_file} ]]; then
                echo $"${base} dead but subsys locked"
                return 2
        fi

        if [ -z "$pid" ]; then
                echo $"${base} is stopped"
                return 3
        fi

        if [ -n "$pid" ]; then
                echo $"${base} (pid $pid) is running..."
                return 0
        fi

}

rh_status() {  
    # run checks to determine if the service is running or use generic status
    my_status $prog
}

rh_status_q() {  
    rh_status >/dev/null 2>&1
}



case "$1" in  
    start)
        rh_status_q && exit 0
        $1
        ;;
    stop)
        rh_status_q || exit 0
        $1
        ;;
    restart)
        $1
        ;;
    status)
        rh_status
        ;;
    *)
        echo $"Usage: $0 {start|stop|restart|status}"
        exit 2
esac  
exit $?  

Nginx

Install Nginx by following this guide.

Add Ghost Nginx config /etc/nginx/conf.d/ghost.conf. Also make sure Nginx default server config is removed in file /etc/nginx/nginx.conf.

server {  
    listen 0.0.0.0:80;
    server_name midgetontoes.com;
    access_log /var/log/nginx/midgetontoes.log;

    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header HOST $http_host;
        proxy_set_header X-NginX-Proxy true;

        proxy_pass http://127.0.0.1:2368;
        proxy_redirect off;
    }
}