Welcome Back & How to Run a Ghost Blog for Free

Welcome Back to the rootshellz blog

Hello world! It's been quiet some time since I've put any effort at all into this blog. However, I still enjoy writing about new things I am learning about and experimenting with, so I figure it's time I revive the rootshellz blog! My main interest is still security, so the content will mostly be related, but there will also be general technology-related content as well, such as this article.

The Problem

There is no shortage of blogging platforms these days. There are fully managed solutions ranging from the free WordPress.com and Medium.com, to ad-supported Wix.com, to paid premium managed platforms like Wordpress.org and Ghost.org. There's also the "old-school" more hands-on method of self-hosting a blog. Many of the same services offering hosted solutions also offer their software for use on self-hosted sites. This includes Wordpress and my personal favorite, Ghost.

What if, like me, you want the flexibility of a self-hosted solution, without the cost of a managed solution, but with the high-availability and reliability of a paid-platform? That would certainly be too much to ask for, right? Not so fast!

The Solution

In the rest of this article, I will outline how I use a local version of the open-source version of Ghost in conjunction with Docker and Mr Mo's ghost-static-site-generator to produce a static blog that is hosted for free using GitHub Pages and then add the ability to comment using Disqus, another free service. The result is this blog that you are reading right now!

Motivation

So why use this method?

Pros

  • Free. You can run a blog (or website) with nothing out of pocket. Add a few dollars a year if you want to have your own domain.
  • Minimal upkeep. No OS or web server to patch; No node.js to update; etc.
  • Minimal attack surface. No web server to accidentally misconfigure, no outdated software to forget to patch, no dynamic content requiring potentially vulnerable backend code, and no database to steal data from or insert malicious code into. (Caveat: this is assuming GitHub does it's part, but they have a great reputation.)
  • Site will theoretically be as highly-available and scalable as GitHub.com itself.

Cons

  • Everything published is public, for (mostly) forever. Since the entire site is hosted within a GitHub repository, even removed content will exist within the commit history. The exception here is if you delete the repo and re-create it with fresh history, which is totally possible, but not documented here.
  • You lose all dynamic features like default commenting systems, user registration and related functionality, and scheduling publication of posts in the future. You will have no dynamic backend. If you really need features like these, this is probably not the best setup for your blog or site.
  • You are at the mercy of GitHub. If the site goes down, there is nothing you can do. There is also a risk that GitHub discontinues or otherwise changes their pages offering or ToS.
  • No access control. You can't limit your site to only certain users or IP addresses.

How to Ghost Tutorial

Let me first say, there are multiple way to accomplish this end result, including using platforms other than Ghost, but this is the way I do it and it work for me. I have updated this process with slight variations over the years.

Components

  • Ghost - Free-to-use, open-source blogging platform written in node.js. This is the tool that will allow us to actually manage our blog and publish new articles and content.
  • Docker - Container-based virtualization platform. This will allow us to easily run some necessary tools locally, without worrying about mucking up our local environment.
  • Mr Mo's ghost-static-site-generator - This is a tool that will "freeze" our locally hosted Ghost blog, converting it from a local-only dynamic blog to a set of static assets that we can deploy to a website hosting platform.
  • GitHub Pages - This allows us to host our blog for free on GitHub.com by deploying out static assets to a properly configured git repository. This gives our site all the reliability of GitHub. It also means we get some freebies like managed TLS including a free CA-signed certificate, although since our site is static, this is mostly for the lolz.
  • Disqus - A free-to-use comment system that is popular across the Internet. Users with a Disqus account will be able to comment on pages on our site. (Scroll to the bottom of this article and leave a comment using Disqus now!)
  • Optionally, you also can use a custom domain name purchased from your choice or providers. My registrar of choice is Namecheap.

Process

This is the process I use to run this blog:

First of all, you will need two GitHub.com repositories. One private repository to hold your actual Ghost site database and assets, for local editing. I call this repo blog.rootshellz.com. This repo should remain private. The second repo should be public and configured for GitHub pages. I call this repo rootshellz.github.io.

To set up the public repository to be served by GitHub Pages:

  1. Create the repository (make it public)
  2. Open the repo in your browser and select Settings.
  3. Scroll down to the GitHub Pages section.
  4. Select the appropriate branch to enable pages.
  5. If you have a custom domain name, enter it. (You will also need to add a CNAME to point your domain to GitHub – e.g. blog 300 IN CNAME rootshellz.github.io.)
  6. Optionally, enable Enforce HTTPS. Do it, why not?

From here, it's just a matter of installing Docker and following this workflow:

Work on the private repo locally:

  • Clone the private, "back-end" repo: e.g. git clone git@github.com:rootshellz/blog.rootshellz.com.git
    • or just git pull from inside of the correct existing directory
  • Create a new branch for the changes you are going to make: git checkout -b creating_new_post
  • Launch the local Ghost blog via a Docker container with Ghosts's content mapped as a volume:
    • docker run -d --name ghost -e url=https://blog.rootshellz.com -p 3001:2368 -v /Path/to/private/repo/blog.rootshellz.com/ghost/content:/var/lib/ghost/content ghost (Replace the mapped path with the correct path to your private repo.)
  • Once running, you will now be able to view the Ghost site locally and make changes using Ghost UI.
    • Viw your site locally: /
    • Access the admin panel to make changes: /ghost
  • After you have made the desired changes, using Ghost's web interface, commit them to the private repo:
    • git add -A
    • git commit -m "Making some changes"
    • git push
    • If you didn't push straight to the master branch, go to GitHub and create a pull request (PR) for the changes and merge into the master branch.

Now, we will be syncing the back-end changes to the public repository:

  • Clone the public, GitHub Pages, repo: e.g. git clone git@github.com:rootshellz/rootshellz.github.io.git
    • or just git pull from inside of the correct existing directory
  • Create a new branch for the changes you are going to sync. These will be your published changes to the public site: git checkout -b creating_new_post
  • Blow everything away: rm -rf /Path/to/public/repo/rootshellz.github.io/*
    • This is required to correctly sync everything, otherwise content removed from your site locally won't be removed on the production site. Be sure to remove the content inside of the repo (.../*) instead of the repo itself (.../). This should preserve hidden files and directories, importantly including .../.git.
  • "Freeze" the blog using ghost-static-site-generator. The tool runs on node.js, so it's easiest to use a Docker container so as to avoid mucking with a local node setup.:
    • docker exec -it $(docker run -dt --name gssg --network="host" -v /Path/to/public/repo/rootshellz.github.io:/ghost_static node /bin/bash) /bin/bash (Replace the mapped path with the correct path to your public repo.)
    • From inside of the container, run:
      • npm install -g ghost-static-site-generator
      • gssg --domain https://blog.rootshellz.com --url https://blog.rootshellz.com --dest ghost_static/ (Replace the argument after the --url flag with your actual URL.)
      • Re-add the CNAME: echo your.domain.com > ghost_static/CNAME (e.g. echo blog.rootshellz.com > ghost_static/CNAME)
      • Exit the container: exit
  • Sync the local changes to the public repository:
    • git add -A
    • git commit -m "Makeing some changes"
    • git push
    • If you didn't push straight to the master branch, go to GitHub and create a pull request (PR) for the changes and merge into the master branch.
      • Any changes merged to the master branch (or whatever branch you defined in the GitHub Pages settings above) will now by published and live on your site!
  • Cleanup the Docker containers:
    • docker rm -f ghost
    • docker rm -f gssg

Comments

The final piece to this puzzle is to add comment functionality to our blog (or site). We do this using Disqus. There are multiple ways to accomplish this, but I followed this method published by Disqus and endorsed by Ghost. Other options involve simply adding Disqus-provided JavaScript to the footer of every page, using Ghost's Code injection functionality.

Follow these steps using the above process for making changes to your private repo and then syncing them to the public, GitHub pages repo:

  • Sign up at Disqus and register a new site.
  • Copy the Ghost-Disqus comment code (provided by Disqus).
<div id="disqus_thread"></div>
<script>
    var disqus_config = function () {
        this.page.url = "{{url absolute="true"}}";
        this.page.identifier = "ghost-{{comment_id}}"
    };
    (function() {
    var d = document, s = d.createElement('script');
    s.src = 'https://EXAMPLE.disqus.com/embed.js';
    s.setAttribute('data-timestamp', +new Date());
    (d.head || d.body).appendChild(s);
    })();
</script>
  • Paste the comment code into post.hbs for whatever theme you are running. (For me, this is under /Path/to/private/repo/blog.rootshellz.com/ghost/content/themes/the-shell-master/post.hbs.) Note that some themes may have default Disqus code built in, but I just replace it with the Disqus provided code.
  • Replace the example in the line s.src='https://EXAMPLE.disqus.com/embed.js'; with your unique Disqus info. (e.g. mine becomes s.src='https://rootshellz.disqus.com/embed.js';
  • After doing the "sync-to-prod dance" as defined above, you should now see Disqus comment functionality at the bottom of your blog posts.

Conclusion

There you have it. Follow this process and you too can easily self-publish a professional quality blog for free using Ghost, GitHub Pages, and Disqus.