How-To Install Ghost on Ubuntu 16.04

How-To Install Ghost on Ubuntu 16.04

comments

Ghost is the blogging platform that I use for this site. It's a light-weight, fast and fully customizable alternative to WordPress.

Ghost is built with Node.js, while WordPress uses PHP. In benchmarking tests, Node.js consistently outperforms PHP by a lot.

Some of the features include:

  • AMP integration
  • Ghost Desktop App
  • Markdown content editing
  • RSS subscriptions
  • SEO friendly - canonical tags, permalinks, semantic markup, XML sitemap
  • Twitter Cards & Facebook Open Graph

In this guide I'll show you how to download, configure and run ghost as a system service and set-up a reverse proxy for it using Apache2 or Nginx.

Requirements

  • Ubuntu 16.04 LTS
  • Apache2 or Nginx

How to install Ghost

Create a new user for Ghost to run under

sudo adduser --disabled-login --gecos 'Ghost blog' ghost

Add NodeSource Node.js v6.x repo

curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -

Install Node.js v6.x

sudo apt-get install -y nodejs

Install knex-migrator

sudo npm install -g knex-migrator

Download Ghost

cd /var/www/ericmathison.com/
wget -O blog.zip https://ghost.org/zip/ghost-latest.zip
unzip blog.zip -d blog

Install Ghost

npm install --production --prefix /var/www/ericmathison.com/blog/

Create the configuration file

nano config.production.json

Add your blog's details to the configuration file:

{
    "url": "https://your-website-url-here/",
    "server": {
        "host": "localhost",
        "port": 2368
    },
    "database": {
        "client": "mysql",
        "connection": {
            "host"     : "localhost",
            "user"     : "your-username-here",
            "password" : "your-password-here",
            "database" : "your-database-name-here"
        }
    },
    "auth": {
        "type": "password"
    },
    "paths": {
        "contentPath": "content/"
    },
    "logging": {
        "level": "info",
        "rotation": {
            "enabled": true
        },
        "transports": ["file", "stdout"]
    }
}

Set permissions

sudo chown ghost:www-data -R /var/www/ericmathison.com/blog/

Initialize the database

NODE_ENV=production knex-migrator init

Set-up a reverse proxy


Apache web server

Add your website's information to the configuration file

sudo nano /etc/apache2/sites-available/ericmathison.com.conf
<VirtualHost *:80>
     ServerName ericmathison.com
     ServerAlias www.ericmathison.com
     ProxyRequests off
     ProxyPass / http://127.0.0.1:2368/
     ProxyPassReverse / http:/127.0.0.1:2368/
     ErrorLog /var/www/logs/ericmathison.com/ericmathison_error.log
     CustomLog /var/www/logs/ericmathison.com/ericmathison_access.log combined
</VirtualHost>

Enable website in Apache

sudo a2ensite ericmathison.com

Reload Apache

sudo service apache2 reload

Nginx

Create a configuration file for your domain.

sudo nano /etc/nginx/sites-available/ericmathison.com
server {
    listen 80;
    server_name ericmathison.com;

    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header HOST $http_host;
        proxy_set_header X-NginX-Proxy true;

        proxy_pass http://127.0.0.1:2368;
        proxy_redirect off;
    }
}

Create a symbolic link for the configuration file

sudo ln -s /etc/nginx/sites-available/ericmathison.com /etc/nginx/sites-enabled/

Make sure there's no syntax errors in your Nginx config file

sudo nginx -t

Restart Nginx

sudo service nginx restart

Add Ghost as a system service

sudo nano /etc/systemd/system/ghost.service

Add configuration details to file

[Unit]
Description=Ghost
After=network.target

[Service]
Type=simple

WorkingDirectory=/var/www/ericmathison.com/blog
User=ghost
Group=ghost

ExecStart=/usr/bin/npm start --production
ExecStop=/usr/bin/npm stop --production
Restart=always
SyslogIdentifier=Ghost

[Install]
WantedBy=multi-user.target

Start Ghost

sudo systemctl enable ghost.service
sudo systemctl start ghost.service

Your Ghost blog should now be up and running!

ghost-service-status

How do you run more than one Ghost blog on the same server?

It's simple. For each Ghost blog installation, you'll need to run it on its own unique port. You can specify the port in the config.production.json file.

Troubleshooting


ETIMEDOUT error

I was getting a ETIMEDOUT error when trying to initialize the database.

I knew my credentials were correct and that the MySQL server was running. So what could it be? Why was it timing out when trying to connect to it?

I pinged localhost and sure enough that was the problem.

ping localhost
PING localhost.com (74.125.224.72) 56(84) bytes of data.

There was no entry for localhost inside of /etc/hosts. And I'm using Google's DNS servers, so they were resolving localhost to localhost.com. That's where it was trying to connect to.

A simple line in /etc/hosts fixed it: 127.0.0.1 localhost

NODE_ENV=production knex-migrator init
[2017-09-07 16:40:09] ERROR

NAME: InternalServerError
CODE: ETIMEDOUT
MESSAGE: The server has encountered an error.

Error: connect ETIMEDOUT
    at Connection._handleConnectTimeout (/var/www/ericmathison.com/blog/node_modules/mysql/lib/Connection.js:419:13)