Installing Ghost on Azure Web Sites
I love beer.
I digress, let's get to it.
First and foremost, big thanks to William Dibbern of the Ghost development team. He and I worked together to solve the issues we saw with Express and Express-hbs because of the Azure UNC paths. He was always quick to respond and handled the dirty work of submitting issues and pull requests. Thanks, William, we ought to have a beer together sometime.
That said, there are quite a few ways to get Ghost up and working with Azure. This post will touch on the following two:
Lastly, this post assumes you're using the SQLite option. If you'd like to use MySQL, it's certainly an option with Azure, but this post does not cover the setup for that piece of it.
You'll need an Azure account, so if you don't already have one, go ahead and create one. This, of course, will also require you to have a Microsoft account, so if you don't already have one, go ahead and create one.
If you just signed up, welcome back.
Create an Azure Web Site
First things first, let's create an Azure Web Site. Login to the Azure Portal. Click on 'Web Sites' and 'New' at the bottom of the screen and select 'Quick Create'. You'll be prompted to enter a URL or name for your web site. This must be unique to Azure and your site will be accessible using the name you provide in the format of yoururlname.azurewebsites.net. You'll still have the option, at any time, of choosing to use a custom Azure domain.
In under a minute, the web site should be created and you'll see the notification appear.
The web site will be defaulted into 'Free' mode. If you want a custom domain, you'll have to upgrade to 'Shared' mode. Pricing for Azure is reasonable, and as of this writing, 'Shared' mode is under $10 per month.
From here, select the web site and enter into the dashboard.
Configure Azure FTP
On the dashboard, click on 'Set up deployment credentials'.
You'll be prompted with a dialog to enter a user name and password. You'll use these credentials when you FTP to the web site. Store these somewhere. Preferably somewhere secure. You'll need them in a bit.
If you were to create multiple Azure Web Sites, you can use this same user name and password for FTP access across all of them.
When you FTP to your Azure Web Site, your user name will be in the following format:
Deployment from GitHub or Git
This step assumes you have your Ghost source code hosted in GitHub or a local Git repository.
Before you proceed with this step, do the following:
You'll have to bump the Express version in the
package.json (found in the root of the Ghost source code) from
"express": "3.3.4" to
"express": "3.4.0". If you're reading this and the version is already
3.4.0 or greater, you have nothing to change. This requirement is because of an Azure bug in Express that was resolved in
If you haven't already done so, copy the Ghost configuration file,
config.example.js, over to a new file named
You'll want to update the
production property within
config.js. Swap out the value of
url with the URL web site that you created. You can copy that value from 'Site URL' under the dashboard of your web site. Additionally, you'll want to set the port to
production property should look something like this:
Within the Ghost folder, install Grunt,
npm install -g grunt-cli, bring in the Ghost dependencies via
npm install, precompile the Sass and Handlebars via
grunt prod -- all in that order.
Create a new file in the Ghost root called
server.js and add this line of code to it:
var GhostServer = require('./index'); This file is required for Azure Web Sites to detect that it is a Node.js application.
Commit all changes to your Git repository. Note that the
.gitignore will exclude
config.js files. These files are required, so I'll leave it up to you if you wish to bypass and commit them or FTP them to your site after deployment.
Next up, select 'Set up deployment from source control' on the Azure Web Site dashboard.
Here you can select 'GitHub' or 'Local Git repository'. If you choose 'GitHub', keep reading otherwise use this Azure Node.js Git tutorial and return to the Azure Configuration section below after the publish.
When you proceed, you'll be prompted to log into GitHub and accept the permissions that Azure is asking for. Afterwards, you'll be prompted to select the repository containing your Ghost source code and the branch that you'd like to target.
Assuming success (GitHub or Git), you'll see something like this:
Note that Azure automatically processes the
package.json and pulls down the submodules. Lastly, as you make changes to your GitHub or Git repository, you can seamlessly sync those changes without having to run thru this blog post again. Yay!
Azure Web Sites have iisnode baked into the IIS pipeline. It allows you to run Node.js applications within IIS. If you love Node, you should say hello to iisnode - it has some benefits. I should probably blog about it - it's impressive in its own right. Anyways, this works to our advantage because we don't have to install and/or setup Node.js on the Azure Web Site, it's just there waiting for us, in stealth, if need be.
Node.js environment variables
When Ghost runs, it reads from
config.js to determine, for example, where to read/write data from. Assuming a production environment, you'll want set the Node.js environment variable,
Click on the 'Configure' tab on your web site and scroll down till you see 'app settings'. Add in
NODE_ENV with a value of
production. Do not forget to click 'Save' at the bottom of the screen!
Azure web.config and iisnode.yml
Alright, it's time to FTP. Grab the FTP credentials that you stored in a secure location earlier and open up your favorite FTP client. Copy the FTP URL from your web site dashboard under 'FTP host name'.
Open up your FTP client, enter your credentials and connect to your Azure Web Site.
If you didn't already commit
config.js files to Git, now would be the time to FTP them.
This is completely optional, but you might be interested in logging your output and error streams. You can do so by adding the following within the
In this context, logs will be found under
/site/wwwroot/iisnode/ - you can change this to whatever makes you happy.
We're almost done!
Hack for Azure UNC Support
Update: If you're using a version of Ghost that uses
express-hbs 0.5.0 this step is no longer needed. Hooray!!
This step is only required if, within the
package.json of your Ghost source code, you are running
"express-hbs": "0.2.2". The first release of Ghost,
0.3.0, uses this version.
An upcoming express-hbs fix should soon negate this step. However, I have not tested it yet. I'll be sure to do so when it's released. Stay tuned to this blog for further information about this issue.
If you're new to Node, I don't condone what I'm about to show you. If you're not new to Node, ummm, close your eyes, skip over the next section and spare me in the comments.
That said, there are other ways to do this, but a hack is a hack is a hack... and we all do it from time to time.
Update: The pull request above was not entirely complete. If you are using Ghost containing
express-hbs 0.3.0, replace
/site/wwwroot/node_modules/express-hbs/lib/hbs.js _with this hbs.js from a pull request that will, hopefully, soon negate this hack all together. If you are using a version of Ghost containing
express-hbs 0.2.2, continue with the steps below.
Swap out the
cachePartials() function with the following.
That wasn't so bad, was it? That said, please don't ever associate my name with the aforementioned. Too late, eh?
In all seriousness, if you don't know any better, usually you want to avoid hacking your
node_modules. These are your project dependencies which are not typically stored with your application source code. They are automatically pulled in based on your
package.json via an
Instead, if possible, find a work-around in your application or submit a pull request to said module and begin using that version in your
package.json. (Says the guy who did neither... my options are limited and, while I'd love to help out, I'm not on the Ghost development team.)
If you successfully followed my instructions, you can navigate to the URL of the web site you just created.
Ghost, simple, beautiful, blogging, is ready for ya!
(If you receive an error when navigating to the URL, try restarting the web site within the Azure Web Site Portal.)
Any questions, comments, concerns or free beer, please reach out to me via Twitter and/or the comments below.