Ghost.js on CentOS

Ghost.js is clean blogging only software with minimalistic design aesthetics and responsive web design. It comes with pretty decent functionality out of the box and its themes can be extended easily using handlebars. The bhira.net blog is running on Ghost.js and I wrote this post as a recollection of the steps I followed in setting up this server. This post describes how to setup Ghost.js blogging software on a CentOS server. These instructions are meant for a production server and will use MySQL for storage and run nodejs using pm2 (process manager for Node). Nginx is used as a proxy server for nodejs.

Here are the main steps:

  • Setup MySQL
  • Setup Nginx
  • Setup nodejs
  • Setup ghost.js
  • Setup pm2
  • Setup theme


SETUP MYSQL

  1. Install Remi repository for CentOS 6 which depends on Fedora EPEL repository
  2. Check available MySQL versions
    • yum –enablerepo=remi list mysql mysql-server
  3. Install MySQL
    • yum –enablerepo=remi install mysql.x8664 mysql-server.x8664
  4. Start MySQL and enable auto start on boot
    • /etc/init.d/mysqld start
    • check for errors in /var/log/messages
    • check for errors and temp root password in /var/log/mysqld.log
    • chkconfig –list | grep mysqld
  5. MySQL secure installation
    • /usr/bin/mysqlsecureinstallation
    • mysql -u root -p
    • >> show plugins;
    • >> uninstall plugin validate_password;
    • >> set password for ‘root’@‘localhost’ = ‘new-password’;


SETUP NGINX

  1. Install nginx yum repository
  2. vi /etc/yum.repos.d/nginx.repo
    • [nginx]
    • name=nginx repo
    • baseurl=http://nginx.org/packages/centos/6/$basearch/
    • gpgcheck=0
    • enabled=0
  3. yum –enablerepo=nginx install nginx
  4. chkconfig –list httpd
  5. chkconfig –level 3 httpd off
  6. chkconfig –level 3 nginx on
  7. service start nginx
  8. vi /usr/share/nginx/html/index.html
  9. vi /etc/nginx/nginx.conf
  10. vi /etc/nginx/conf.d/default.conf
  11. nginx log rotation - /etc/logrotate.d/nginx
    • edit config: vi /etc/logrotate.d/nginx
    • test run: /etc/cron.daily/logrotate
#FILE: /etc/nginx/nginx.conf

user  nginx;
worker_processes  1;
error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
  include       /etc/nginx/mime.types;
  default_type  application/octet-stream;

  log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

  access_log  /var/log/nginx/access.log  main;

  sendfile on;
  keepalive_timeout 65;
  gzip on;
  server_tokens off;
  include /etc/nginx/conf.d/*.conf;
}
#FILE: /etc/nginx/conf.d/default.conf

server {
    listen       80;
    listen       [::]:80;
    server_name  localhost www.my-server.com;

    location /robots.txt {
        alias /usr/share/nginx/html/robots.txt;
    }

    location / {
        proxy_pass http://127.0.0.1:2368;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header HOST $http_host;
        proxy_hide_header X-Powered-By;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}
#FILE: /usr/share/nginx/html/robots.txt

User-agent: *
Sitemap: http://my-server.com/rss


SETUP NODEJS

yum -y update
yum -y groupinstall "Development Tools"

# ----- upgrade g++ and set in bash env -----
sudo curl http://linuxsoft.cern.ch/cern/scl/slc6-scl.repo > /etc/yum.repos.d/slc6-scl.repo
sudo rpm --import http://ftp.mirrorservice.org/sites/ftp.scientificlinux.org/linux/scientific/51/i386/RPM-GPG-KEYs/RPM-GPG-KEY-cern
sudo yum install -y devtoolset-3
scl enable devtoolset-3 bash
g++ -v

cd /usr/local/src
wget http://nodejs.org/dist/node-latest.tar.gz
tar zxf node-*.tar.gz
cd node-v*
./configure
make
make install
node --version
npm --version


SETUP GHOST.JS

cd <install dir>
npm install -g grunt-cli
wget http://ghost.org/zip/ghost-latest.zip
Unzip ghost-latest.zip
npm install --production
mv config.example.js config.js
vi config.js
    ...
    // ##use gmail
    mail: {
      service: 'Gmail',
      transport: 'SMTP',
      host: 'smtp.gmail.com',
      secureConnection: true,
      port: 465,
      options: {
        auth: {
          user: 'email@gmail.com',
          pass: 'my-gmail-password'
        }
      }
    },

    // ##use mysql
    database: {
      client: 'mysql',
      connection: {
        host     : '127.0.0.1',
        user     : 'mysql-user',
        password : 'mysq-user-passwd',
        database : 'mysql-db',
        charset  : 'utf8'
      },
      pool: {
        min: 2,
        max: 20
      }
    },
    ...

# run node in production mode
NODE_ENV=production node index.js


SETUP PM2

  • sudo /usr/local/bin/npm install -g pm2
  • vi /etc/init.d/ghost
  • chmod 755 /etc/init.d/ghost
  • chkconfig –add ghost
  • chkconfig –list ghost
  • vi /etc/logrotate.d/pm2
  • service ghost start
#!/bin/bash
#
# FILE: /etc/init.d/ghost
# processname: ghost
#
# chkconfig: 345 80 20
#
### BEGIN INIT INFO
# Provides: ghost
# Required-Start: $local_fs $remote_fs
# Required-Stop: $local_fs $remote_fs
# Should-Start: $network
# Should-Stop: $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
### END INIT INFO

export NODE_ENV=production
export HOME=/home/myuser

NAME=ghost
PM2=/usr/local/lib/node_modules/pm2/bin/pm2
NODE=/usr/local/bin/node
USER=myuser

APP_DIR=/home/myuser/ghost
APP_START=index.js
APP_NAME=$NAME

super() {
    su -l $USER -c "$1 $2 $3 $4 $5 $6 $7 $8"
}

start() {
    echo "Starting $NAME"
    cd $APP_DIR
    super NODE_ENV=production $NODE $PM2 start ${APP_DIR}/${APP_START} -x --name $APP_NAME
}

stop() {
    echo "Stopping $NAME"
    cd $APP_DIR
    super NODE_ENV=production $NODE $PM2 stop ${APP_DIR}/${APP_START} -x --name $APP_NAME
}

restart() {
    echo "Restarting $NAME"
    stop
    start
}

status() {
    echo "Status for $NAME:"
    cd $APP_DIR
    super $NODE $PM2 list
    RETVAL=$?
}

case "$1" in
    start)
        start
        ;;
    stop)
        stop
        ;;
    status)
        status
        ;;
    restart)
        restart
        ;;
    *)
        echo "Usage: {start|stop|status|restart}"
        exit 1
        ;;
esac
exit $RETVAL
# FILE: /etc/logrotate.d/pm2

/home/myuser/.pm2/logs/*.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    sharedscripts
    copytruncate
    dateext
}


SETUP THEME

Now you’re all set with Ghost running on your CentOS server and you can start configuring your blog. Ghost includes a pretty extensible framework for creating themes and I’ve created one named casper-slidr. You can read more about this theme or download it for GitHub.