Install multiple Ghost blogs in one Linux server with nginx


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
tar xfz Python-2.7.5.tgz
cd Python-2.7.5
./configure --with-threads --enable-shared
make altinstall

ln -s /usr/local/bin/python2.7 /usr/bin/python2.7
echo "/usr/local/lib/python2.7" > /etc/
echo "/usr/local/lib" >> /etc/

2. Installing NodeJS


Install Epel

curl -O
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

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: '',
    mail: {
               transport: 'SMTP',
            options: {
                    service: 'your SMTP server',
                    auth: {
                            user: '',
                            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: '',
        // 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


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

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;

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";

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.