Running Ghost on Windows and IIS.

I just couldn’t leave it alone...

So only one day after setting up my blog on a cloud hosted Ghost instance, I’ve found myself trawling through blogs and documentation on a voyage of discovery – with the intent of hosting Ghost on my own NodeJS server.

Why?!

You may want to just skip to the instructions.

When I made the decision to go with Ghost, the thinking was that I didn’t want to get bogged down in the creation of a website or management of blog software... instead reasoning that the content I wanted to post should take the highest priority.

That thinking still stands, however I really wasn’t comfortable with the lack of overall control I had without hosting the system myself.
In no particular order, here’s what was concerning me:

URL management

Ghost Pro allowed me to use my own domain... that’s great, but I also want to host other things.

As I’m getting into game development, I’d need a place for the games I make. Many of my posts will contain code. Ghost handles this well, but I also need to post demos of said code. Those demos may be HTML5 and Javascript, they may be CFML, PHP, any number of other technologies as I progress...
The only solution seemed to be to separate these concerns across various sub-domains. I’m not happy with this solution as conceptually, this is all one site.

Hosting Ghost myself, allows me to place the blog content under a subfolder, and allows other content to exist wherever I like.

No SSL

Wait, what? Seriously?
Apparently I can use SSL if I host through CloudFlare, which I have no intention of doing. Otherwise I’m stuck with standard non-secure hosting.

Theme development

I found I had no way of previewing changes I made to my theme as I have no local version of the Ghost software.
Additionally, the workflow seems to be:

  • Make a change
  • Save the file
  • Create a zip file of the entire theme
  • Upload it to Ghost
  • Refresh the browser
  • Repeat

That’s insane! My usual workflow of Alt-Tab, F5 is infuriating enough already... I really need to get some live reload functionality working, but I’ve run into problems with that on Windows. Apparently Grunt is the way forward there, but I've yet to delve into that beyond build minification... I’ll get there eventually.

So if I host the software myself, I can at least save and refresh.

Node JS, baby!

Over the last few years I’ve found myself using Javascript more and more, out of sheer necessity. I’ve been planning to embrace this a little more and start dabbling with Node.js for server side development for some time.
I’ve run Node locally for some basic Grunt build tasks, but I’ve not really advanced beyond that. Hosting Ghost necessitates running a Node.js instance on a live server, and getting my hands dirty a little.

My hope is that as I want to add bits and pieces to the site outside of Ghost, I will attempt to do that with Node first.

But I still love CFML...

I do. It’s true.
CFML made me a developer.
Years of experience made me a pretty good one.
Contracting and inheriting code made me confident enough to make that last statement... There’s nothing quite like inheriting god-awful code, to combat impostor syndrome!

So while I want to get out of my comfort zone and start developing for Node, I’d like to know that if I just need to get something done I can switch back to old faithful, by hosting Node alongside a Lucee instance.

I can’t see the database!

Yeah. That just doesn’t sit well with me. Ghost apparently has a nice API in beta that will allow me to pull content out and do whatever I want with it, sure... but there’s nothing quite like delving into the database and bending the data to my will.

No. If there’s an option that allows me to access the DB, I’m taking it.

And so, to work!

With the decision made, it’s time to get down to it.
Installing Node is straight forward. The homepage of https://nodejs.org points directly to the download. We want the LTS version, since that’s what Ghost is supporting.

IISNode

I want to run Node through IIS. Partially because I want to be able to use other technologies on the same site and partially because it’s what I’m comfortable with. I also don’t fancy opening up more ports on my server.

IISNode seems to be what I’m looking for here: https://github.com/tjanczuk/iisnode
Setup is a straight forward installer and running a batch file adds a bunch of samples on the default website.
Initially, these samples don’t work and I receive the following error:

The iisnode module is unable to start the node.exe process. Make sure the node.exe executable is available at the location specified in the system.webServer/iisnode/@nodeProcessCommandLine element of web.config. By default node.exe is expected in one of the directories listed in the PATH environment variable.

A quick Google shows I need to restart the WAS service, thus:
net stop was /y & net start w3svc

I’m now able to see the hello world sample. That was fairly painless... hurrah!

Installing Ghost

Again, this is fairly straight forward. Download the latest version of Ghost, https://ghost.org/download/ & unzip the contents to a folder under the webroot.
Open a command prompt, navigate to the folder containing the Ghost installation and run the following command:
npm install –-production

Updating the config.

I now have a version of Ghost installed, but before I start it I need to mess with some config settings.
In the root of the Ghost setup is a file, config.example.js. If I run Ghost now, it’ll copy that over to a new file, config.js. I may as well do this myself.

In the config.js file there are a few settings we need to change.

url: Set the URL of your blog.
email: In order to send password reset emails, we need to tell Ghost about our email setup.
Detailed instructions are here: http://support.ghost.org/mail
server: Since we’re using IIS, we need to tell Ghost to let IIS decide the port.
port: process.env.PORT

Update web.config

We need to tell IIS to forward requests to node. In the root of the Ghost installation, add this to the web.config under:
<configuration><system.webServer>

<handlers>  
    <add name="iisnode" path="index.js" verb="*" modules="iisnode" />
</handlers>  

We now want to route all traffic through the Ghost node app, whilst allowing other javascript to be executed client side, so we can use the rewrite module:

<rewrite>  
    <rules>
        <rule name="Ghost">
            <match url="/*" />
            <conditions>
                <add input="{PATH_INFO}" pattern=".+\.js\/debug\/?" negate="true" />
            </conditions>
            <action type="Rewrite" url="index.js" />
        </rule>
    </rules>
</rewrite>  

Finally, we want Ghost to handle any 404 responses for missing URLs - by default IIS will be handling them.

<httpErrors existingResponse="PassThrough" />  

Thanks to Lubomir Kamensky for the tip.

Setting up the database

I notice the installation has created an SQLite instance for my data. I’m much happier with MySQL or MSSQL, and after a bit of Googling it seems I’m not alone.

I create a new database my MySQL instance, grant access to a new user and add the following details to the config.js file:

    client: 'mysql',
    connection: {
        host: 'localhost',
        user: 'YourUsername',
        password: 'YourPassword',
        database: 'YourDBName',
        charset: 'utf8'
    },

Running Ghost

I read a lot of articles during the course of setting this up. Most of the ‘Ghost on Windows’ tutorials include a manual starting of the app, using Npm start –production.

What’s not been made clear, but actually makes sense now that I think about it, is that this isn’t required when using IISNode. The module will automatically start the Node app if a request is made to the URL.
Thus, you can now visit your blog URL and you should see the default Ghost blog homepage!

Hurrah! You now have a working Ghost installation on IIS.
Hopefully.

A note on environments

Node has an understanding of different environments out of the box, using the NODE_ENV setting. You may have noticed in your config.js, there were settings for both development and production environments.

Ghost runs in development by default, but obviously on a production server you’ll want to change this.
Since IISNode is starting the app for us, we can’t simply set the environment in the command line, but we can change the default in the /core/index.js file, thus:
process.env.NODE_ENV = process.env.NODE_ENV || 'production';

I’m not overly happy with this, for two reasons. Firstly I don’t feel right editing anything in the core. Presumably updates will overwrite this setting, so it’s something to remember whenever you update Ghost.
Secondly, this messes with my version control. I don’t want to have to have a different setting on dev than in production and usually create some form of conditional sever interrogation to avoid this.

For now however, I can’t seem to find another way of doing this – short of having the .js file auto updated by something else server-side.

Update: Using HTTPS

When deploying on my production server, I found that the site was returning an infinite redirect.
It turns out that if you try to use an https url, you need to add a header to the request. I found a github fork of Ghost specifically for Azure, and this had the answer:

Create a file in your Ghost root called iisnode.yml, and add the following:

node_env: production  
loggingEnabled: true  
logDirectory: iisnode  
enableXFF: true  
nodeProcessCommandLine: "%programfiles%\nodejs\node.exe"  

You may need to update the last line with your location of the Node executable.
Not only does this work, but it also overrides this line in web.config:

<iisnode node_env="%node_env%" loggingEnabled="true" nodeProcessCommandLine="&quot;%programfiles%\nodejs\node.exe&quot;" />  

And that’s about it! It was quite a hassle to get everything working the first time around, but to deploy on production I simply followed my own instructions and by and large it was all pretty smooth.

Now as I want to add other areas to the site, I’ll have the choice of Ghost static pages, or integrating CFML, or whatever I like really.
Sky’s the limit!

Comments