Install multiple Ghost blogs in one Linux server with nginx

Ghost

Yesterday I decided to migrate my blog from WordPress to Ghost because I think Ghost is the right platform for my blog. Ghost is running under Node.js which requires me to move my blog to new server.

There's a official documentation how to install Ghost in several platform, but as of 18/10/2013 there's no manual how to setup multiple Ghost blogs running in one server yet.

I decided to use nginx to act as reverse proxy for Node.js.

1. Install Python 2.7.5

Install development tools

yum -y groupinstall 'Development Tools'
yum install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel

Install and config Python

cd /tmp
curl -O http://python.org/ftp/python/2.7.5/Python-2.7.5.tgz
tar xfz Python-2.7.5.tgz
cd Python-2.7.5
./configure --with-threads --enable-shared
make
make altinstall

ln -s /usr/local/bin/python2.7 /usr/bin/python2.7
echo "/usr/local/lib/python2.7" > /etc/ld.so.conf.d/python27.conf
echo "/usr/local/lib" >> /etc/ld.so.conf.d/python27.conf
ldconfig

2. Installing NodeJS

CentOS/RHEL

Install Epel

curl -O http://download-i2.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
rpm -ivh epel-release-6-8.noarch.rpm

Instal Node.JS

yum install npm

3. Install Ghost

As of I posted this article, v0.3.2 is the latest Ghost.
The Ghost will be installed in /home/ghost

useradd ghost
su ghost
cd /home/ghost
wget https://ghost.org/zip/ghost-latest.zip
unzip ghost-0.3.2.zip

Install and run

npm install --production
npm start

Modify config.js

nano config.js

Specify the address and port for Ghost installation in config.js
It might looks like this

// ### Production
// When running Ghost in the wild, use the production environment
// Configure your URL and mail settings here
production: {
    url: 'http://fuad.me',
    mail: {
               transport: 'SMTP',
            options: {
                    service: 'your SMTP server',
                    auth: {
                            user: 'postmaster@vmgamer.mailgun.org',
                            pass: 'password'
                            }
                    }
    },
    database: {
        client: 'sqlite3',
        connection: {
            filename: path.join(__dirname, '/content/data/ghost.db')
        },
        debug: false
    },
server: {
        // Host to be passed to node's `net.Server#listen()`
        host: '127.0.0.1',
        // Port to be passed to node's `net.Server#listen()`, for iisnode set this to `process.env.PORT`
        port: '2222'
    }
},

Make Ghost run forever

npm install -g forever
NODE_ENV=production forever start index.js

To show running Ghost

forever list

To stop Ghost

forever list
forever stop 0 # if 0 is Ghost process

Or

forever stopall

4. Setup nginx as reverse proxy

Install nginx

yum install nginx

Configure nginx to act as reverse proxy

mkdir /etc/nginx/sites-enabled/
nano /etc/nginx/sites-enabled/ghost

Configure and optimize nginx webserver, edit /etc/nginx/nginx.conf

user nginx;
worker_processes 4;
pid /var/run/nginx.pid;

events {
worker_connections 768;
# multi_accept on;
}

http {

##
# Basic Settings
##

sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;

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

##
# Logging Settings
##

access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;

##
# Gzip Settings
##

gzip on;
gzip_disable "msie6";

gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

##
# Virtual Host Configs
##

include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}

Modify following Ghost virtualhost in /etc/nginx/sites-enabled/ghost

server {
listen         80;
server_name {your-blog-address};
root /home/ghost/;
access_log /home/ghost/access_log.log;

if ($http_host != "{your-blog-address}") {
     rewrite ^ http://(your-blog-address)$request_uri permanent;
}

location / {
    proxy_set_header X-Real-IP  $remote_addr;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header Host $host;
    proxy_pass http://127.0.0.1:2222;
}

location ~* \.(?:ico|css|js|gif|jpe?g|png|ttf|woff)$ {
    access_log off;
    expires 30d;
    add_header Pragma public;
    add_header Cache-Control "public, mustrevalidate, proxy-revalidate";
    proxy_pass http://127.0.0.1:2222;
}

location = /robots.txt { access_log off; log_not_found off; }
location = /favicon.ico { access_log off; log_not_found off; }

location ~ /\.ht {
        deny all;
}
}

Start nginx

service nginx start

The blog should be accessible via the URL stated in above configs.
To run another Ghost installation, just modify the user, installation directory, running port, and add another virtualhost to /etc/nginx/sites-enabled/ghost.