Note: The repository used in this post is way out of date, and I don't recommend following this article any more. Check out this post on deploying the newer version of Ghost Blog.

I have thoroughly enjoyed getting to know Ghost. I've found it a light, clean and fun blogging engine. However as simple as it is to deploy it, there's more to it if you want to customise or in my case add comments, email and a backup process.

TL:DR;
I needed a process for customising my blog that gave me more control. I forked the Ghost-Azure repos and went about integrating DisQus for comments and setting up an Azure backup into blob storage.  This post explains how I did that.

I ended up re-deploying and changing the way I managed my blog and I thought I'd share what I ended up deciding on.

Steps:

Setting up SendGrid Mail Service in Azure

Let's get this setup first, as Ghost will try to send you an email when it's first fired up.

  • Login to the Azure portal
  • Click More Services (bottom left)
  • Type SendGrid
  • Click SendGrid Accounts

  • Fill in the details and select a pricing tier. I'm not going to be sending many emails so Free was the right price for me.
  • Click Create

You may need to click the refresh button, but once you can see your new account, click it, and then click on the cute little key icon.

Take note of your username, you'll need it for the deployment configuration.
You'll also need to use this should you want to login to SendGrid for more configuration options.

Fork Ghost-Azure

Why? This just makes it easier to add your customisations such as Comments Integration and avoid them being accidentally overridden if you re-sync your blog with the original repository. This meets my requirement of having customisations in source control and also ensures that when you want to upgrade you can merge any changes that might conflict and do this when it suits you.

Felix Rieseberg has done a great job of making deploying ghost simple. BTW You can also search for the Ghost template in the Azure market place and deploy from there, but I found this version out of date at the time, and also has the same problem of potentially losing your comment integration should you re-sync in future.
(If you don't already have a GitHub account, create one https://github.com/)
Open Felxi's repo here: https://github.com/felixrieseberg/Ghost-Azure, then click Fork.

This is now your forked version of Ghost-Azure. Let's just get Ghost setup and running before trying to implement the comments.

Deploy to Azure

In the ReadMe you should see an inviting blue button "Deploy to Azure", go ahead and click it. To Clarify, this is the ReadMe in your forked repository.

Note: That the Azure Deployment site you are on has read the referrer url and that's how it knows where to get the source from, you can see it in the address of the browser.

After logging in using your Azure credentials, you should see the deployment options:

Here's an example I've filled out. Some of these fields are auto populated for you which makes things very straight forward.

Here's the fields:

  • Directory - Leave as default
  • Resource Group - A way to keep your resources together for easier location of services, use an existing or create a new.
  • Site Name - this will become [sitename].azurewebsites.net and you will use it for Editing your posts. Even if you have a custom domain.
  • Sku - If you want to use the automatic backup, you'll need to set this to Standard. Basically it will be the App Service Plan which determines your costs (along with the Site Location and Worker Size). If you want to make this cheaper later (and lose the backup function), you can always Scale Down your service plan by clicking Scale Up.
    Scale Up Hmm, why doesn't that sound right?
  • Site Location - This is the data centre you want to use.
  • Worker Size - Only available for basic and standard, this also determines your billing cost. It is the resources assigned to that Tier. You can see this in the Azure Service Plan:

    Small Medium and Large are the first, second and third panels respectively.

It's well known that the data centers have varying prices and last I looked the West US was a better price than anything here in Australia. However if you want to know your costings before running this, go into the Azure Pricing Calculator.

  • Email Service - I'm using SendGrid, because its free and easy to use. Your blog will need this for password reset requests and team member invites.
  • Email From - Use your custom domain if you have one, or make one up. I'd not really want to put my personal email address in there. Be aware there is a good chance your emails will go to your Junk folder. For more information check the SendGrid documentation.

Follow the wizard and wait for the deployment to finish. If you're wondering what's happening here, Azure is processing the azuredeploy.json, which is a Resource Manager Template with instructions on how to deploy and setup your blog. It's worth pointing out as well where some of the configuration values end up, like your Email Username etc. Take a look in the App Settings of your App Service:

Of course I've left my password in the image in case any of you want to use my account... 12345 is about all I can remember so I use it for all my passwords.

1,2,3,4,5... That's amazing. I've got the same combination on my luggage.

One thing I've heard is that if you deploy to a Basic or Free tier, there might not be enough resources for the initial deployment, so if you have trouble here try starting on the Standard Tier, then down grade once you are up and running.

Using a Custom Domain

One thing you may want to do is add your public url to the webSiteUrl setting. I've got a custom domain, if you don't have one just leave it blank and it will work on the azurewebsites.net domain.
This is probably where I should add a link to another post around assigning a custom domain. (To be continued...)

Setup Ghost

Access your blog using the https://[sitename].azurewebsites.net/ghost. This will take you to the admin area, and should put you in HTTPS mode. This is quite straight forward, so I won't go into detail here.

Setup your comment provider

I'm using DisQus, which is pretty popular, but there are others. However I'm only going to show how to integrate with DisQus.

  • Create the account
  • Choose your pricing model
  • Register a new site
  • Under the community settings I'd recommend NOT allowing guests to comment (for spam reasons)
  • Make sure to add the correct public url in the General Website URL field. This should be the same URL that people will browse your blog on is not necessarily your azurewebsites.net url.

Integrate Comments

What you need to do now (and why we forked the Ghost-Azure repo from Felix) is to modify the post.hbs template in the Casper theme. Casper is the default theme in Ghost, if you upload a different theme you'll need to do similar steps here.

Let's clone the repository by, opening a GIT command shell and running:

git clone https://github.com/TjWheeler/Ghost-Azure
cd Ghost-Azure

Make sure to change the Url to match your repository.

Tip: If the GIT command line gives you the heeby jeebies, try out the GitHub desktop app. Saying that, it's worthwhile getting familiar with the command line so I'd recommend giving it a go if you haven't used it yet.

Git Command Shell

Browse to your repository and locate the following the post.hbs Handlebars template: X:\Repos\Ghost-Azure\content\themes\casper\post.hbs.

Edit the file, and insert the following after the </Footer> element:

 <section class="post-full-comments">
                <div id="disqus_thread"></div>
                <script>
                    var disqus_config = function () {
                        this.page.url = '{{url absolute="true"}}';
                        this.page.identifier = 'ghost-{{id}}';
                    };
                    (function () {
                        var d = document, s = d.createElement('script');
                        s.src = 'https://yourdisqususername.disqus.com/embed.js';
                        s.setAttribute('data-timestamp', +new Date());
                        (d.head || d.body).appendChild(s);
                    })();
                </script>
            </section>

Update 29/06/2018: Originally I was using {{comment_id}} however I found this didn't work. I have since changed to use the post id {{id}} and that seems to work correctly.

In the above snippet, you'll want to change yourdisqususername to your actual DisQus Username.
Save the file.
Go back to your GIT session, and run:

git add .

This will add all modified files into the staging area, essentially getting them ready to commit.
To commit this change run:

git commit -m "Adding DisQus Comment Integration"

That's committed to your local repository now (on your file system). To push this change to GitHub run:

git push

Great! We're done with comment integration, let's go sync our Repo with Azure!

Jump into the Azure portal, select your Blog under the App Service, then click on Deployment Options.

Hit the Sync button then click Yes.

Azure's going to update your blog now.

This could take a minute or two, or way longer...
Hopefully you've got a tick and everything's cool, if not you can click the View Log link for error details.
Browse back to your blog, open the default post (in preview or live mode, not edit mode) and you should see your comments:

Web Job - Step 1 for daily backups

When I first setup Azure to backup I ran into a snag when I tested out the restore process (everyone remembers to do that right?). The database file in the archive was 0 bytes. Ok, so the file is locked, Azure backup ran, couldn't read it, continued and showed me a Partially Suceeded Result. After a quick search I found a great post by Tom Chantler who'd run into the same issue. Better yet, he created a simple solution and threw it into GitHub for anyone to use. Thanks Tom, much appreciated!

One thing when deploying your Web Job, you will need to enter the schedule using the Cron format, I used *0 0 3 * * ** which means 3am every day.

Tom's post covers the subject really well so I won't go over it here. But this is a good solution if you want to configure your daily backup and actually have it backup properly.

Configure a backup schedule - Step 2 for daily backups

Now on to the Azure backup feture for App Services.
Select your Blog in your App Services area, then click Backup.

Enter a schedule that suits you and click Save. You probably want the Web Job to run a couple of hours before this one to get the latest days posts.

I'd recommend coming back here in a day or so, looking at the last backup and downloading it. Extract the zip and make sure you can find your backup.db file.

Final thoughts

I know this is a pretty long post, but I realised I spent a bunch of time researching how to get all these features into my ideal blog solution. There are lots of good posts on how to do most of what I've covered, but I wanted to show a complete picture which will hopefully help people be aware of what it really takes to setup a robust blogging solution.

Or at a pinch, just use one of the many online blog services and forget all this hassle. If you do, keep in mind you have a lot less control over that system, it could shutdown at some point and if you are planning on building your brand, you may want your own domain and full control over any customisations.

My final thoughts on this are that it meets my requirements but may not meet yours. Here's what I was looking for:

  • Markdown support
  • Publish in the server (rather than generating static files for deployment)
  • Daily Backup
  • Comments
  • Source Controlled Customisations
  • Easy to learn, work with and maintain
  • A good upgrade path (Honestly, I am not quite sure if I've got this one yet)
  • Drag and drop image support
  • Code syntax highlighting (requires a bit more work here)
  • Host in Azure

Anyways, keep on truck'n.... and blog'n.