Ghost Blog with Nginx on Ubuntu


Ghost is a platform dedicated to one thing: Publishing. It’s beautifully designed, completely customisable and completely Open Source. Ghost allows you to write and publish your own blog, giving you the tools to make it easy and even fun to do.

In this tutorial, I will show you how to host a Ghost blog on Ubuntu, using Nginx as your web server.

Last Updated: 31st January 2015.


  1. Installing Git
  2. Installing Node.js
  3. Installing Ghost
  4. Installing Nginx
  5. Basic Nginx Configuration
  6. Nginx Blog Configuration
  7. Making Ghost Run Forever

Installing Git

You should install Git before installing anything else:

sudo apt-get install git

Installing Node.js

The best way to install Nodejs is using Chris Lea’s Launchpad repo, his repo contains both npm and Nodejs:

sudo add-apt-repository ppa:chris-lea/node.js
sudo apt-get update
sudo apt-get install python-software-properties software-properties-common python g++ make
sudo apt-get install nodejs

Verify that Nodejs has been installed:

node -v

Installing Ghost

Installing Ghost is a very straightforward process.

You need wget and unzip before you can proceed any further, if you don’t have it then:

sudo apt-get install wget unzip

Get a copy of the latest version of Ghost:

cd ~
wget ""
unzip -d ghost

Before you can install Ghost, you need to make some changes to the config.js file:

cd ~/ghost
cp config.example.js config.js
nano config.js

Navigate to the Production section of the file, it will look something like this:

// ### Production
// When running Ghost in the wild, use the production environment
// Configure your URL and mail settings here
production: {
    url: '',
    mail: {},
    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: '2368'

Things that you need to change:

  • URL: change it from to your site’s domain name.
  • Mail: add your email settings inside mail: {}. For more information on mail settings, feel free to peruse through Ghost’s Offical Docs.

Install Ghost in production mode, first make sure that you are in ~/ghost directory, then:

npm install --production

This might take a while, just be patient and let Ghost install all of its dependencies.

After the installation is complete, go ahead and start Ghost:

NODE_ENV=production npm start

You should get an output similar to this:

> ghost@0.3.3 start /home/talal/ghost
> node index

Ghost is running...
Listening on
Url configured as:
Ctrl+C to shut down

This means that Ghost has been installed correctly and is working as it should. Go ahead and stop Ghost by pressing Ctrl + C, then proceed to the next step.

Installing Nginx

There are several ways to install Nginx but the best one (in my opinion) is to use the Nginx Launchpad repo maintained by the Nginx team.

sudo add-apt-repository ppa:nginx/stable
sudo apt-get update
sudo apt-get install python-software-properties software-properties-common
sudo apt-get install nginx
Testing Nginx

To check if Nginx was installed correctly; you will first need to start Nginx, if it isn’t running already:

sudo service nginx start

Then, go to your server’s public IP address in your web browser, there you will see the Nginx landing page which looks something like this:

Nginx Welcome Page

If you don’t know your server’s public IP address then try this:


You will need curl for the above command to work, if you don’t have it installed then:

sudo apt-get install curl

If you see the Nginx landing page then it means that Nginx has been installed properly and you are ready to move on to the next step.

Controlling Nginx Daemon

If Nginx is running and you wish to stop it:

sudo service nginx stop

If Nginx is stopped, then to start it:

sudo service nginx start

To restart Nginx (stop and then start it again):

sudo service nginx restart

If you have made any changes to the Nginx configuration files then you don’t necessarily need to restart Nginx, you can just reload the configuration files:

sudo nginx -t && sudo service nginx reload

Basic Nginx Configuration

Now that you have Nginx installed, the first thing that you should do is configure the main Nginx configuration file.

You can use the Nginx defaults, but I like to optimize and fine-tune the configuration file:

sudo mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.default
sudo touch /etc/nginx/nginx.conf
  • The first command will backup the current nginx.conf file; just a precautionary measure.
  • The second command will create a new blank nginx.conf file for us to work on.

Open the .conf that you just created sudo nano /etc/nginx/nginx.conf and then paste the following configuration in it:

# nginx Configuration File

# Run as a less privileged user for security reasons.
user www-data;

# How many worker threads to run;
# "auto" sets it to the number of CPU cores available in the system, and
# offers the best performance. Don't set it higher than the number of CPU
# cores if changing this parameter.

# The maximum number of connections for Nginx is calculated by:
# max_clients = worker_processes * worker_connections
worker_processes auto;

# Maximum open file descriptors per process;
# should be > worker_connections.
worker_rlimit_nofile 8192;

events {
  # When you need > 8000 * cpu_cores connections, you start optimizing your OS,
  # and this is probably the point at which you hire people who are smarter than
  # you, as this is *a lot* of requests.
  worker_connections 8000;

# Default error log file
# (this is only used when you don't override error_log on a server{} level)
error_log  /var/log/nginx/error.log warn;
pid        /var/run/;

http {

  # Hide nginx version information.
  server_tokens off;

  # Define the MIME types for files.
  include       /etc/nginx/mime.types;
  default_type  application/octet-stream;

  # Update charset_types due to updated mime.types
  charset_types text/xml text/plain text/vnd.wap.wml application/x-javascript application/rss+xml text/css application/javascript application/json;

  # Format to use in log files
  log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

  # Default log file
  # (this is only used when you don't override access_log on a server{} level)
  access_log /var/log/nginx/access.log main;

  # How long to allow each connection to stay idle; longer values are better
  # for each individual client, particularly for SSL, but means that worker
  # connections are tied up longer. (Default: 65)
  keepalive_timeout 20;

  # Speed up file transfers by using sendfile() to copy directly
  # between descriptors rather than using read()/write().
  sendfile        on;

  # Tell Nginx not to send out partial frames; this increases throughput
  # since TCP frames are filled up before being sent out. (adds TCP_CORK)
  tcp_nopush      on;

  # Compression

  # Enable Gzip compressed.
  gzip on;

  # Compression level (1-9).
  # 5 is a perfect compromise between size and cpu usage, offering about
  # 75% reduction for most ascii files (almost identical to level 9).
  gzip_comp_level    5;

  # Don't compress anything that's already small and unlikely to shrink much
  # if at all (the default is 20 bytes, which is bad as that usually leads to
  # larger files after gzipping).
  gzip_min_length    256;

  # Compress data even for clients that are connecting to us via proxies,
  # identified by the "Via" header (required for CloudFront).
  gzip_proxied       any;

  # Tell proxies to cache both the gzipped and regular version of a resource
  # whenever the client's Accept-Encoding capabilities header varies;
  # Avoids the issue where a non-gzip capable client (which is extremely rare
  # today) would display gibberish if their proxy gave them the gzipped version.
  gzip_vary          on;

  # Compress all output labeled with one of the following MIME-types.
  # text/html is always compressed by HttpGzipModule

  # This should be turned on if you are going to have pre-compressed copies (.gz) of
  # static files available. If not it should be left off as it will cause extra I/O
  # for the check. It is best if you enable this in a location{} block for
  # a specific directory, or on an individual server{} level.
  # gzip_static on;

  include sites-enabled/*;

Nginx Blog Configuration

Now, you can create a server block for your Ghost blog, it will be located in /etc/nginx/sites-available/.

For the sake of this tutorial, I will assume that your domain name is You will need to replace with your blog’s domain name, wherever it is mentioned.

Create the configuration file for your blog:

sudo nano /etc/nginx/sites-available/

And then paste the following configuration in it:

server {
  listen 80 default_server;

  # The host name to respond to

  location / {
        proxy_redirect     off;
        proxy_set_header   Host             $host;
        proxy_set_header   X-Real-IP        $remote_addr;
        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;

In order to take your blog live on the internet, you will need to symlink it to /etc/nginx/sites-enabled/

sudo rm -R /etc/nginx/sites-enabled/default
sudo ln -s /etc/nginx/sites-available/ /etc/nginx/sites-enabled/

Restart Nginx:

sudo service nginx restart

At this stage, you can access your Ghost blog by going to your blog’s domain name in your web browser. You can also access Ghost’s dashboard (admin panel) by going to

Making Ghost Run Forever

The previously described method for running Ghost: npm start, will keep Ghost running as long as the npm process is running in the terminal. As soon as you close the terminal or log out from your server, Ghost will stop running.

To prevent this, you need to install Forever. Forever will keep Ghost running as a background task and if for some reason Ghost crashes then it will restart it.

Install Forever:

npm install forever -g

Start Ghost using Forever:

cd ~/ghost
NODE_ENV=production forever start index.js

If you need to stop Ghost, then:

cd ~/ghost
forever stop index.js

Thats it!