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

/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;
}

/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;
    }
}

/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

/etc/init.d/ghost

#!/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  

/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.

Baldeep Hira

bay area programmer working on mobile/tablet/web apps and enterprise cloud apps; ui/ux, html5 and everything else for a prettier web and world

  • San Francisco Bay Area
comments powered by Disqus