I’ve been wanting to spin up a blog lately and document the things I’ll be studying and working on. So, I thought the best bet would be Ghost, which you can get at ghost.org.
At the time of writing, Ghost’s most recent version is 1.22.0. I had already installed it and had no major trouble making it work on my Windows Server 2016 instance with IIS 10. Although this wasn’t the same instance and I had no idea I was about to spend hours trying to manually install Ghost. It was crazy, it mattered not how many times I tried, there was always something that didn’t work, until I found a few good references online around 2 am in the morning that did the trick.
I’ll document it here in case someone wants to attempt the same thing later, including me.

First of all, I needed to install the ghost CLI:

npm install -g [email protected]

Set some environment variables:

set NODE_ENV=production
set GHOST_DIR=<website's root path>

Install Ghost and create a default configuration:

ghost install --db sqlite3 --no-prompt --no-stack --no-setup --dir "%GHOST_DIR%"
cd "%GHOST_DIR%"
ghost config --ip --port 2368 --no-prompt --db sqlite3 --url http://mydomain.com

Run the database migrations:

ghost setup migrate

This command will ensure that the Ghost database exists, the tables are created and the fixtures are inserted.

Adjust the config file

Open your config.production.json file, change the blog's public URL and delete the server port. IISNode will inject it later:

  "url": "https://www.blogname.com",
  "server": {
    "host": ""

If you want to run your current installation you can set a variable for the port using set server__port=2368, then run node current/index.js. Ghost should run successfuly.

Index redirect

Create an index.js file in your root folder. This will be the entrypoint for IISNode:

process.env.server__port = process.env.PORT;

Our index.js file now forwards the port given to us by IISNode to the environment variable that Ghost is expecting. This will also avoid setting the entry point to current/index.js in the IISNode configuration, which would cause the working directory of the node process to be set to our current folder, which would in turn stop Ghost from finding the configuration file.

The web.config

And this is what my web.config loos like, for reference. If you don't have one, please create it.

			<remove name="WebDAVModule" />
			<clear />
			<remove name="WebDAV" />
			<add name="iisnode" path="index.js" verb="*" type="" modules="iisnode" scriptProcessor="" resourceType="Unspecified" requireAccess="Script" allowPathInfo="false" preCondition="" responseBufferLimit="4194304" />
		<iisnode node_env="production" enableXFF="true" nodeProcessCountPerApplication="1" />
				<rule name="ghost">
					<match url="/*" />
					<action type="Rewrite" url="index.js" />

Notice the <remove name="WebDAVModule" /> part in the web.config file. This was added because even though Ghost was running successfully, I wasn't able to save settings or create new posts. Ghost would throw a 405 error while trying to execute a PUT request, which being hampered by the WebDAV module. Thus, I removed it.

And this I show I got Ghost running again!

I would like to thank Robert Schmid from Germany and Kevin Ansfield from the Ghost Slack! Both helped me getting this thing up.