The software behind CKDSN.com is an open source publishing platform called Ghost. Ghost is great.

[note: At some point I decided to have Ghost host/manage the site instead of doing it myself. As such, these instructions won't be updated as I'm no longer involved in the site management/upgrading/running process. That said, hopefully they're still useful (for a while, at least). ~CK]

My web host uses a third party auto installer that installs Ghost for users, and for the past year or so I've relied on the auto installer for my base Ghost install and software updates. The time savings was nice. However, the updates didn't always work and my ability to make adjustments to Ghost was limited, if, for no other reason, because I didn't know what was going on behind the scenes.

As such, I decided to blow it all up and do a fresh install of Ghost on my own... and I think it worked! There are still some kinks to work out, but it feels fairly functional and stable.

Getting the website from "Let's go for it[1]... let's start over" to "OMG I did it! It super works again!!"[2] was a journey, involving many a hushed, "Oh no... did I make a huge mistake?"[3]

Here is a list of the landmarks for anyone else out there who might need it. (Or, more likely, for me to use in the future.)

  1. Prereqs
  2. Where to start
  3. Install Node.js and NPM
  4. Installing Ghost
  5. .htaccess
  6. Create your database
  7. Create a MigratorConfig.js file
  8. Install and run knex-migrator
  9. Create a config.production.json file
  10. Start the site (hopefully)
  11. Parting Thoughts

Prereqs

What comes before anything? What have we always said is the most important thing?

Back-ups. Always make a back-up.

Specifically, if you already have a Ghost blog, you should go to the Labs section of your admin area and export your blog as a JSON file. When you're done setting everything up, you can re-import that same file to recover your entire site.

Also, how comfortable are you in a terminal window? Can you SSH into your account? Most of the work took place inside a terminal window, remotely running commands via SSH.

I used a MySQL database (which I named something other than "ghost"[4]). Finally, for what it's worth, my laptop runs Linux.

Learn from my mistake
It turns out my site's SSH credentials are much different than what I use to access my web hosting account. Make sure you're using the right username and password.

Where to start

There are a few different ways to install Ghost and one of the larger challenges is figuring out which path you want to travel. For my main set of instructions, I used a blend of:

Ghost CLI sounds amazing; I'm pretty sure it's currently incompatible with my web host.[5]

Install Node.js and NPM

Start by installing Node.js. You can use node --version and npm --version to see if it's already installed.

The installation process probably differs depending on your web host -- find specific instructions for your host, if you can.

If the instructions you're using are outdated, you should be able to find the latest stable release of Node.js here. From there you can easily enough swap out the pertinent text in the commands. e.g.
wget https://nodejs.org/dist/v4.4.1/node-v4.4.1-linux-x64.tar.xz
becomes
wget https://nodejs.org/dist/v6.11.2/node-v6.11.2-linux-x64.tar.xz

Installing Ghost

I'm pretty sure installing Ghost was fairly straight forward, once I picked the right commands... it didn't work immediately, but I think that was mostly due to incorrectly configured configuration files.

I mostly used my web host's instructions for this part, with some wisdom from Ghost sprinkled in.

In hindsight, I wish I would have documented, as it was happening, which commands were successful. I remembering having a few false starts, which I had to undo, before I finally got it right. Looking back through the command line history, I think these three commands were the ones that got the job done:[6]

wget --no-check-certificate https://github.com/TryGhost/Ghost/releases/download/1.7.1/Ghost-1.7.1.zip

unzip -d ghost Ghost-1.7.1.zip

npm install --production

Also, as found on the Ghost NPM site, it looks like I ran npm init inside the Ghost folder at some point. Running npm init creates a package.json file.

.htaccess

I didn't see anything about .htaccess while working through the Ghost via npm documentation. Later, I did find this page: Ghost docs: Redirects. My web host mentions .htaccess, but not until the end of the process.

Personally, I think it makes sense to tackle .htaccess at this point in the process.

My .htaccess/regex knowledge isn't the strongest, but this is what I currently have:

Options +FollowSymLinks -Indexes

IndexIgnore *

DirectoryIndex
<IfModule mod_rewrite.c>

RewriteEngine on

# Simple URL redirect:
# RewriteRule ^(.*)$ http://www.ckdsn.com:8675309/$1 [L,P]
# RewriteCond %{REQUEST_FILENAME} !-f
# RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ http://127.0.0.1:8675309/$1 [P,L]

</IfModule>

You'll need to choose a port value on which Ghost runs. The range may vary, depending on your web host. The value you choose here (8675309 [7] in this case) will be the value you'll use later, in your config.production.json file.

It's worth noting that I have some lines commented out in the code above. The instructions and examples I saw online recommended them; however, activating those lines breaks the site. I plan on investigating more... at the moment things seem to work just fine.

Learn from my mistake
As I mentioned earlier, I think it makes sense to create your .htaccess file before creating your config files. At one point in this process, a few days passed between setting up my config files and creating .htaccess. Since my .htaccess file wasn't gatekeeping, my config files were accessible by simply typing in their URL to a web browser. This is bad, because login credentials are stored in config files.

Once I got .htaccess working, I blew up my first database and created a fresh one with different credentials. #SafetyFirst

Create your database

I was able to create a MySQL database in the administrative area of my website. There was an area conveniently titled "MySQL Databases". (My web host uses cPanel, your experience may vary.)

Once you create the database and create a new user account for the database, you're done. We'll initialize the database in a later step.

Let's use the following values for the fake site that we're building in this post:

  • Database name: ckdsn_newdatabase42
  • Username: ckdsn_newdatabase42
  • Password: tHePaSsWoRdIsPaSsWoRd

Note: the username and the database name are the same. It's something I saw in other examples online, and I mirrored it. It doesn't seem to break anything and it makes it easy to keep track of which user goes with which database.

Create a MigratorConfig.js file

Set up your MigratorConfig.js file... my file looks like this:

var config = require('./core/server/config'),
    ghostVersion = require('./core/server/utils/ghost-version');

/**
 * knex-migrator can be used via CLI or within the application
 * when using the CLI, we need to ensure that our global overrides are
triggered
 */
require('./core/server/overrides');

module.exports = {
    database: {
        client: 'mysql',
        connection: {
            host: 'localhost',
            user: 'ckdsn_newdatabase42',
            password: 'tHePaSsWoRdIsPaSsWoRd',
            charset: 'utf8',
            name: 'ckdsn_newdatabase42'
        }
    },
    migrationPath: process.cwd() + '/core/server/data/migrations',
    currentVersion: ghostVersion.safe,
    database: config.get('database'),
    migrationPath: config.get('paths:migrationPath')
};
            

You can see where I've updated the user, password, and name values with ckdsn_newdatabase42, tHePaSsWoRdIsPaSsWoRd, and ckdsn_newdatabase42, respectively.

Install and run knex-migrator

First, install knex-migrator: npm install -g knex-migrator[8]

Next, navigate to your Ghost folder, which is where your MigratorConfig.js file should be, and run knex-migrator: NODE_ENV=production knex-migrator init

Once the migrator is running, you should see status updates as it initializes tables and columns in your database, if I remember correctly.

Learn from my mistake
The Ghost documentation says to run this:
NODE_ENV=production knex-migrator init --mgpath node_modules/ghost. That command produced an error saying the migrator couldn't find the MigratorConfig.js file.

The option --mgpath specifies where to find the config file, in this case node_modules/ghost. However, the documentation I read places the file in the project root, which meant this part of the command was pointing to the wrong folder. Removing --mgpath node_modules/ghost resolved the error.

Create a config.production.json file

In theory, a person should create a development environment for Ghost and do all their debugging and testing there, before going live. I didn't do that. As such, I skipped creating a development config file and went straight to a production file.

My config file is below. I cobbled together what seemed important from A) my old Ghost config file (which was formatted slightly differently), B) a Ghost sample config file, and C) my web host's instructions.

{
    "url": "http://www.yourwebsite.com",
    "database": {
        "client": "mysql",
        "connection": {
            "host": "localhost",
                "user": "ckdsn_newdatabase42",
                "password": "tHePaSsWoRdIsPaSsWoRd",
                "database": "ckdsn_newdatabase42",
                "charset": "utf8",
                "insecureAuth": true,
                "socketPath": "/tmp/mysql.sock"
        },
	"auth": {
            "type": "password"
        },
	"paths": {
            "contentPath": "content/"
        },
        "logging": {
            "level": "info",
            "rotation": {
                "enabled": true
            },
         "transports": ["file", "stdout"]
        }
    },
    "server": {
        "host":"0.0.0.0",
        "port":"8675309"
    }
}

Again, you'll want to insert your own values for at least a few lines:

"url": "http://www.yourwebsite.com",

"user": "ckdsn_newdatabase42",

"password": "tHePaSsWoRdIsPaSsWoRd",

"database": "ckdsn_newdatabase42",

"port":"8675309"

Start the site (hopefully)

The final big step is starting the site. There are two ways to do this. The Ghost documentation has the following, which I believe runs in the ghost folder:
NODE_ENV=production node index.js

This command is great for seeing if the blog runs at all... it gives you details on what's going right and wrong so you can troubleshoot.

That said, once you close the terminal window (or the connection times out) the website goes down. To have the site up and running permanently I used the following: nohup npm start --production &

This command should keep things up and running indefinitely. That said, if you're getting errors, you won't know about it. (There's a file called nohup.out which gives you some information. I haven't spent much time looking at it, though.)


Update: 2017-09-27
A couple of weeks ago, the site went down... I'm not sure what happened, but a friend had already warned against using nohup; I figured the crash was as good a reason as any to check out another option. I did some more searching through Ghost's documentation and found forever, which has been working, so far:

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

You can find more information about forever on npm's forever page and in Ghost's forever documentation.


Parting Thoughts

Good luck! Here's a list of the links I personally found helpful, for some reason or another, while getting Ghost up and running.


Updated 2017-09-27


  1. A link ↩︎

  2. Another link ↩︎

  3. One last link ↩︎

  4. I recall getting a random error message at some point, saying that I couldn't install something as a dependency of itself. The solution was definitely as simple as renaming... something. Unfortunately, I can't recall which two things were in conflict, or which process was generating the error. I think the problem was that I was trying to call my database "ghost" and I also had a "ghost" folder in my file tree. I remember, with slightly better (but still not complete) certainty, that renaming the database to something besides "ghost" fixed the error. ↩︎

  5. I went down that path, since the Ghost documentation recommends it every other page, and eventually got an error message saying that my server wasn't on the correct version of Linux to run Ghost CLI. Combined with another troubling error message (I forget exactly what it was) I decided to abandon the Ghost CLI option. ↩︎

  6. It's possible that this command from the Ghost documentation was the critical piece: npm install ghost@1.7.1 --save. The trail of the former looks hotter, for what that's worth. ↩︎

  7. My auto installer picked a port for me, and I reused that number during this process. I don't actually know how one goes about selecting a port for this sort of thing. ↩︎

  8. I don't think it matters where you run this command, but I'm not certain. ↩︎

  9. At some point in the process I got a warning that I should switch out node-uuid and swap in uuid. I ignored it at the time and, while writing up this documentation, remembered it was a thing I should maybe do.

    I just did it, and it didn't seem to break anything. In fact, it may have helped with some ckdsn.com vs www.ckdsn.com redirect problems I was having, but that could just be a coincidence. ↩︎