Creating a Massively Scalable Blog with Ghost, MySQL and Azure

2 min read

Continuing my little series on “deploying things to Azure with shell scripts” I decided to convert my WordPress script to one for Ghost. It took me about 30 minutes to tweak things, but ultimately I was successful!

Once again: the main point of deploying a blog like this is the simplicity combined with the scalability. There are no VMs to think about and no databases to manage. Ghost is pulled down in a container, which is charged up based on your service plan which you can scale at any time.

Same with MySQL – but it’s managed for you so there’s a lot you don’t need to worry about.

Rather than piece apart what I did, as with the last post, here’s the entire script in a gist. I’ll describe the fun stuff down below:

Deployment Script for Ghost on Azure

If you’d like to see a breakdown of this script and what each section does, see my last post.

Does this script seem long and opaque to you? I don’t blame you – shell scripts can be a bit impenetrable if you’re not familiar with bash. I tried to add enough comments in there to (hopefully) make it obvious that I’m just orchestrating commands to Azure itself. Also: a lot of the extra lines are there for readability and convenience (such as popping things into a .env file).

I did have to make a few adjustments from the WordPress script file, however. Specifically:

  • I had to pull the Ghost container (obviously)
  • I renamed the app settings so that Ghost could see MySQL
  • It takes a few minutes to get the image together, migrations run and so on so I added a prompt at the end. I’ve consistently seen 502 errors as the app times out on load – you just have a to wait a bit longer for it all to work.

Storage Stuff

WordPress takes care of updating itself pretty well, so I’m generally not worried about overwriting images, themes, plugins and whatnot with the deployment. Ghost, however, is a different story.

Ghost lends itself to tinkering. It’s open source, built on Node, and has a few bits of functionality kind of… well… missing. Things like full-text search, hacking your theme to make it perfect, etc. These are easy to do but if you’re not careful you can overwrite your deployment.

To get around this, you can use Azure Storage simply by enabling a setting:

You can use an app setting called WEBSITES_ENABLE_APP_SERVICE_STORAGE to control whether or not the /home directory of your app is mapped to Azure Storage. If you need files to be persisted in scale operations or across restarts, you should add this app setting and set it to “true”. If you don’t require file persistence, you can set this app setting to false.

I think it’s great that you can do this simply by turning a setting on, but I think this should be the default, don’t you! Well guess what!

The absence of this app setting will result in the setting being “true”. In other words, if this app setting does not exist in your app, you will see the /home directory mapped to Azure Storage. 


These scripts are a lot of fun to roll together and are helping me get to know Azure. I’m hoping to put them into a repo at some point.

  • Great article and a fantastic resource, I really appreciate the effort you put into this. One problem that I ran into when hosting containerised ghost on Azure is that by default ghost doesn’t store information in the ~/home directory which the websites_enable_app_service_storage looks after… which means that your data (uploaded images etc) periodically disappears!

    It might be nice to complete the picture with either the volume mapping which is needed to map the ghost content onto ${WEBAPP_STORAGE_HOME} or whatever ghost config might be necessary to tell ghost itself to put images etc. over there.

    What do you think?

    • From what I understand the ghost bits are automatically put into ~/home but if you’ve seen otherwise then YES – adding that setting would be quite important. Have you seen this happen before (periodic disappearance)? If so – I’ll make sure to fix this.

      • It’s a problem I’ve been struggling with for quite some time – to start with my containerised ghost blog on the Linux app service was doing just fine, then one day it was gone and back at its initial setting! I reloaded the content from the JSON backup, and reimported all my images and then ‘bang’ it went again! In Theory it should be as simple as setting the volume to map the ghost ‘content’ folder into the variable mentioned above, but every time I try that ghost throws a wobbler about migrating. I don’t want to include SSH in my container just so I can get onto it to fix the problem, but I’ve been running out of ideas! (in fact I’ve just had to repair the site again now. scratch my last attempt!)

  • Just noticed – in line 65 you refer to MYSQL_DB=$DATABASE, but $DATABASE isn’t set anywhere. Is that an error, or does $DATABASE have some kind of special default value?


  • >
    %d bloggers like this: