Blogging with Ghost

I share with you below my experience with the blogging system Ghost (version 0.8.0 as of this writing) used for this blog, and the problems that I ran into. This is not an exhaustive survey, but hopefully my experience will be useful to someone out there.

This blog in itself is a working document for the terraAI project regarding open-source crowd-driven AI platform that I am trying to build.

My requirements

Here my are blogging requirements:

  1. Must be open source, so that I am able to modify or host it myself if I want to.
  2. Must be portable, in the sense that I should be able to move the entire thing to another computer (of the same OS of course) by simply copying a directory, with no need to install many components. This is important to me because I find portable software takes a lot less effort to manage in the long run.
  3. Must be relatively easy to turn it into a static website, even if it does not support such a feature out of the box. A static website is treated simply as a collection of static files and can be served from a CDN such as the Amazon S3, and is infinitely more scalable, more stable, more responsive, safer, and much cheaper to host than traditional methods. This is explained further below.
  4. Relatively simple to use and manage. I prefer simplicity over richness, so long as the basic blogging functions are acceptable.
  5. Easy to hack. Having the original source code doesn't quite cut it. I prefer NOT having to hack into the source code to achieve what i want, since it will cause headache later when there is a need to upgrade to a newer version. I mainly want the ability to add my own code on top of it to override the default behavior with ease.

In the end I opted to go with Ghost. Since Ghost more or less meets my requirements above, I did not bother to look further into WordPress. If anyone has insight into using WordPress in the context of requirements above, by all means please enter your comments at the bottom of this post.

A blog as a static website

There are many benefits to having a blog turned into a static website:

  1. More scalable: you no longer have the database or the web server or the virtual hosting machine as the performance bottleneck, so your blog will always load fast even if there are huge number of people accessing it.
  2. More stable: there are way less things to break, since your blog is just a collection of files.
  3. More responsive, i.e., your blog will load much faster.
  4. Safer. There is not much for a hacker to get into. There is no special admin port for databases, or weakness in the web server, etc., for a hacker to exploit. So long as your file-serving host (e.g., Amazon AWS S3, GitHub, etc.) are solid then you will be fine.
  5. Cheaper. It should take only pennies per month to host such a blog on platforms such as S3 (or for free on GitHub). This compares to somewhere close to USD$10 per month when hosted on the smallest virtual instance on Amazon EC2, or Rackspace, etc.

There are, however, some downsides:

  1. More upfront work. I ran into some problem where the tool for conversion to static website does not convert hyperlinks correctly, so I had to write some code to correct that. I also had to create some simple scripts in order to streamline the blog management tasks (e.g., converting to static website, uploading to hosting site, etc.).
  2. More management work. In a normal Ghost setup it would take just a few clicks to publish a post. Here you will have to use separate tools to convert and then upload, which take somewhat more work.

Converting to a static website

Normally a blog cannot be deployed in the form of a static website, because there needs to server-side logic to do work such as storing or finding information in a data base, enforce security control, etc.

However, there are ways to make this happen:

  1. Separate the environments for production where visitor get to read the blog, and the development environment where the blogger writes a blog, change configuration, etc.
  2. The development environment can be either installed on a local computer, or somewhere on the cloud, and accessible only to authorized people. In other words, this environment operates fully and normally as it should, but it is not accessible to others.
  3. The production environment is a static snapshot of the development environment, taken using some tool (I have tried HTTrack and Buster for this).

But what to do with the server-side logic needed for its operations on the production environment? This is handled in two parts:

  1. First you don't do blog management directly on the production environment, so most of the complex server-side logic are not needed there. Instead you'd manage your blog in the development environment, then copy the changes to the production later.
  2. For visitor activities such as commenting or polling, etc., use an outside service for it. For example, you can use DISQUS for supporting comments, and it is pretty easy to do so. Here is a good article How to integrate Disqus Comments with Ghost that shows you how to do this.
Components vs Services

I have explained above how to use a service, such as DISQUS, for supporting commenting by visitors. When compared to, say, using a Comments plugin in WordPress, what are the pros and cons?

Personally I prefer using a service, since it is easier to manage, and it allows me to deploy my blog as a static website (with all the benefits mentioned earlier). Such services also tend to be of higher quality, although you may need to pay for the service if your traffic exceeds certain limits. You can of course create your own services for these, if you know how to code.

At first glance it may seem like we are losing a lot by going with the dumb and thin static website approach, since it means we will lose server-side logic and storage completely. But in fact for the purpose of blogging this is not at all a disadvantage. This is because there are already many high-quality and free services for media display and socialization out there. I would even argue that when considering quality and the need for high-level social interaction, in many cases it is preferable to use external services.

Following are some free services:

  1. Video: YouTube (on-demand, playlist, live, integrated chat), Twitch (live, integrated chat)
  2. Audio: SoundCloud (on-demand, playlist)
  3. Comments: DISQUS (real-time nested comments)
  4. Crowd ranking: sMesh (real-time suggest/vote/rank)
  5. Maps: Google Maps
  6. Crowd emotes: sMesh (real-time emoting in icon or sound with 'crowd chant' effect)
  7. Crowd debate: sMesh (real-time debate in two sides with ranking of arguments)
Deployment

Deploying ghost from development to production can be achieved as follows:

  1. First use a tool such as Buster or HTTrack to dump the contents of your development server into a local directory.
  2. Then use another tool (such as Winscp) to copy the files to a CDN server, such as an Amazon S3 bucket. Here it is assumed that you have configured your S3 bucket to behave like a static website.

Here are the problems that I ran into with Ghost:

  1. In Ghost's config.js (as of version 0.8) if you set url to point to your development server, then the links in the Share this post area, as well as the links inside the RSS generated, will be wrong when deployed. But if you set it to point to your production server, then the other links in the development environment will be wrong and thus makes it harder to work on.

Aside from the problems mentioned above, following are my experience with Buster and HTTrack for dumping the contents of your development server into a local directory. Both have their own share of problems.

Buster

Here are the problems that I ran into with Buster:

  1. As of this writing Buster no longer generate the RSS feed. There is a workaround here for dealing with it using wget
  2. The dev/production link problems mentioned above are tackled using my own code to make corrections.
  3. Hard to get it installed on Windows or earlier version of Linux. Recommend using Ubuntu 14 or later, or equivalent. I ended up using a guest Ubuntu running under Windows 8 through VirtualBox. The guest Ubuntu accesses the Ghost server on the host (instructions here), and pushes the resulting files to the host through a shared folder (instructions here).
  4. I want to use the Casper with sidebar theme for Ghost here, mainly for the purpose of making it easier for visitors to navigate around using the sidebar. This however creates a problem where if the pages put into the sidebar are of the 'Ghost static page' type, then somehow Buster is unable to generate proper static webpages for them, so those become dead links on the resulting static website. One workaround is to publish those NOT as static pages, although that clusters up the list of posts displayed at Ghost home page.

*I ended up using Buster with some amount of custom code to deal with the problem with links, so far it has worked out well. Note that Buster has built-in support for publishing your static website to GitHub, although I have opted to deploy to Amazon S3 instead.
Update: too many links were incorrectly generated by Buster, especially when it involves Ghost static files. Ended up switching back to use HTTrack instead.

HTTrack

Here are what I found about HTTrack:

  1. This tool is available on many platforms, which is a big plus.
  2. It worked well initially, but eventually I got an MIRROR ERROR. Eventually I found that somehow HTTrack does not like my website URL as localhost:2368 (even though this url works fine in a browser), but 127.0.0.1:2368 does work for HTTrack.
  3. HTTrack handles the Ghost static files well (unlike Buster).
  4. The links in the meta tags (e.g., og:image, twitter:image, etc., in the static webpages generated by HTTrack) are getting mangled by HTTrack, which will cause problem when a visitor shares a post to a social media site. Same thing with many external links. The is resolved by changing HTTrack's Scan Rules option to exclude external links that cause problem. Following are some examples of the scan rules used:

    -*/*www.terraai.org*
    -*/*www.google-analytics.com/analytics.js*
    -*/*cdn.mathjax.org*/* 
    -assets/fonts
    

After some back-and-forth, I ended up choosing HTTrack over Buster.

For incremental deployment I do it as follows:

  1. I use the command-line httrack with the --update option as follows

    \bin\httrack\httrack --update http://127.0.0.1:2368 -www.terraai.org -ssl.google-analytics.com -cdn.mathjax.org -assets/fonts
    

    which does not update file timestamps unless necessary.

  2. I use the Winscp Synchronize command for uploading files through a S3 proxy, which uploads only updated files.
Workflow

Given this setup, the general workflow goes as follows:

  1. Edit my blog on my locally-installed Ghost system (under Windows 8.1).
  2. When ready to publish, run a script that executes httrack to dump the website content into a collection of files.
  3. Use winscp to deploy the files to Amazon S3.

Some custom JavaScript code that I wrote took care of problem with incorrect links generated by Buster.

Summary of problems

To summarize, following are some of the problems that I ran into:

  1. Some links were incorrect and still pointing to the development server when deployed. This involves for example the links in the slide-out menu, the links in the Share this post area, the links inside the RSS text when clicking on Subscribe, etc. This requires additional hacking to resolve, for otherwise the result is not usable.
    Solution:
    1. In Ghost's config.js file, set the parameter development-url to point to the production server. This will make the URL in RSS, Share this post, social media links, etc., correct.
    2. Inject custom code into the admin UI's Code Injection area, for the purpose of scanning the webpage for all links and modify to make them work on the development server, the production server, and as static files.
  2. Ghost defaults its link navigation behavior to replace the current page, which I did not like under most circumstances. There is a longish Markdown syntax that supports this, but I am too lazy to use it all over the place.
    Solution: I added a little JavaScript code to convert all applicable links to have the attribute target=_blank.
  3. Since we no longer have server-side logic, we also lose the ability to do things such as sending emails from the server for things such admin password recovery by email, user subscription by email, etc.
    Solutions:
    1. There is no solution for admin password recovery by email, so you just need to be careful not to lose it. Note that this has no bearing on the production environment.
    2. Subscription for new posts by email can be replaced by the RSS feature, which user can subscribe to and read new posts in his/her preferred RSS reader.
    3. User can send email to the blogger owner by client-side email (as opposed to server-side), either using the HTML mail-to feature, or using a contact form.
  4. When trying to share a Ghost post on Twitter, the resulting tweet is not showing the correct description or image. By inspecting the webpage I can see that the meta tags twitter:description and twitter:image:src as created by Ghost contain the correct info. Still not sure what went wrong nor how to fix it.
    Update 1: turns out that Twitter does not like the way my code was changing the meta elements in the page head section (twitter:image:src, twitter:card, and og:image) dynamically. So far the only way to get the image to show in a tweet is to set the post-level header image from the Ghost admin. I would have preferred not using the post-level image (which is too big), and being able to specify any image of my choice embedded in the post.
    Update 2: I ended up setting the post image with the Ghost admin to get the image to show up when sharing on Twitter, and also to show the image on the home page as thumbnail for each post (see the Display Post Images on Home Page link below). The post-level header image is then styled to hidden as per my own taste.
Conclusion

Overall using Ghost for this blog has worked out relatively well. I do have to hack a bit to deal with "incorrect" links arise from converting it to a static website, but it wasn't too bad.

What I like about Ghost:

  1. Easy installation: just unzip the Ghost kit from github and run (assuming that you already have Node.JS). I put it on my Windows laptop and I am able to work on my blog from anywhere, even if I am without an Internet connection.
  2. Simplicity is the strength of Ghost, but it can also be liability if you prefer having many ready-made features.
  3. Markdown is a minimal syntax for marking up your documents with formatting using punctuation and special characters, which is supported by Ghost. It allows me to focus on expressing my thoughts, and not on bells and whistles in the UI.
  4. Easy to hack. I am a programmer and like being able to add features that I want, hopefully in the form of extra code without having to hack into the core of Ghost (for otherwise it will be harder to upgrade Ghost later).
  5. Node.JS. While the use of Node.JS on the server side is moot once it got converted into a static website, it is nonetheless handy if you wish to add some advanced features (such as push notification, real-time communication, etc.) one day.

Overall I thought it was worth the effort converting my Ghost instance into a static website, and relying on external services for anything that might require server-side logic. I would recommend that you give it a try, assuming that you are at ease with doing some light coding in JavasSript/CSS.

Open questions

Please add your comments below if you have answer to any of the following questions:

  1. Where do I put my own code under Ghost? While customizing Ghost to meet my own needs I have added a number of JavaScript, CSS, and data files. Somehow these files are not accessible on production from a browser unless they are placed under /content/images, which is an odd place for these files.

Separately I have also made many enhancements over the standard Ghost. You can find the details about these here.

Other resources
  1. The Ghost publishing platform.
  2. Node.JS. NodeJS is required for running Ghost. Ghost recommends Node v4 LTS.
  3. How to Add Google Analytics to Ghost
  4. Extending the Ghost Default Theme with a Sidebar, Social Navigation Links, Disqus Comments & a Contact Form
  5. Mail Configuration on self-hosted version of Ghost
  6. How to add class in image markdown in Ghost - this is useful for inserting images in the post and then using CSS to style their looks for best effect (e.g., with wrap-around text, better size, etc.)
  7. Adding a contact form to your Ghost blog
  8. Markdown Guide
  9. Ghost academy - tips and tricks about using Ghost.
  10. AWS Command Line Interface - useful for uploading static files acquired using Buster to the Amazon AWS S3 from command line, which is much easier to automate the process.
comments powered by Disqus