How the blog was built part 1 - the static files

How the blog was built part 1 - the static files
Photo by Lauren Mancke / Unsplash

My previous blog was built with BlogEngine.NET and blog post content saved in files on the Azure web server because I didn't want the hassle and the costs of a database.

I decided to leave Azure for AWS because Microsoft decided to change the terms on the developer subscription with free credits that I had had for so many years and needed a new subscription and then pay after 12 months. I didn't want to do that so I thought I might as well go all in into AWS as most of my cloud experience is there anyway.

I had found a bug upgrading BlogEngine, I didn't want to modify any source code and the people maintaining it weren't going to fix the issue. I wanted better support and also able to keep costs dead low or zero.

This meant my requirements for a new blog would be:

  • easy to use and well supported blog app
  • can create a static website
  • easy to backup the content
  • easy to update the static files and upload them
  • hosting costs low or zero

After plenty of googling I decided on Ghost and there were existing tools to use to create static files for hosting. Easy right? Well as it turned out there were quite a few things that didn't go right and at least one rabbit hole entered and escaped to get to this point.

I know I could have incurred some costs with a monthly subscription with Ghost managing it for me but where's the fun in that! I wanted to learn something new and I like having something to write about and share.

Creating the static files

I found this blog article on creating and hosting your static files from your Ghost blog in Google Cloud but I'm using AWS. This section will make some assumptions you have read the article and/or seen the existing code.

The author first created a Docker version of the Ghost blog and used an existing tool to create the static files. This is what I have changed:

  • Copied the files from GitHub.
  • Removed the gcloud.repo file as I'm using AWS.
  • Updated the docker-compose.yml with more configured values.
    - Arguments added for the author e-mail and Disqus site name and version numbers updated. I don't want to use the latest versions because I want predictability in my setup.
    - Environment Ghost domain updated.
    - Additional volumes for the static and backup files to be saved to.
version: '3.4'

    image: stono/ghost:latest
      - net.ipv6.conf.all.disable_ipv6=1
      context: .
        AUTHOR_EMAIL: "[email protected]"
        AWS_VERSION: 2.2.18
        GHOST_VERSION: 4.12.1
        GHOST_CLI_VERSION: 1.17.3
        DISQUS_SITE: 'binarydreams'
    restart: always
      NODE_ENV: production
      - ./data/content/data:/var/www/ghost/current/content/data
      - ./data/content/images:/var/www/ghost/current/content/images
      - ./data/content/settings:/var/www/ghost/current/content/settings
      - ./bin:/usr/local/bin
      - ./data/static:/static
      - ./data/backup:/backup
#      - ~/.config:/root/.config
      - 80:80
  • Next, the Dockerfile had many changes.
    - Replaced the MAINTAINER with the LABEL that uses the AUTHOR_EMAIL argument.
    - Added sudo when getting the dependencies.
    - Replaced the Google Cloud installation with AWS client.
    - A specific version of Ghost will be installed as per the argument.
    - A custom script will replace the variables with the argument values before the Disqus patch is applied to the blog.
FROM centos:8
LABEL org.opencontainers.image.authors=$AUTHOR_EMAIL

# This file runs when the docker image is built NOT when 'up' is used

# Get dependencies
RUN yum -y -q install which curl wget gettext patch gcc-c++ make git-core bzip2 unzip gcc python3-devel python3-setuptools redhat-rpm-config sudo  && \
    yum -y -q clean all

# Install crcmod
RUN easy_install-3 -U pip && \
    pip install -U crcmod

# Get nodejs repos
RUN curl --silent --location | bash -

RUN yum -y -q install nodejs-14.* && \
    yum -y -q clean all

# Setup www-data user
RUN groupadd www-data && \
    useradd -r -g www-data www-data

RUN mkdir -p /var/www && \
    mkdir -p /home/www-data && \
    chown -R www-data:www-data /var/www && \
    chown -R www-data:www-data /home/www-data


# Configuration
ENV GHOST_HOME /var/www/ghost

# Install packages
RUN yum -y -q update && \
    yum -y -q clean all

# Install AWS utilities
RUN export PATH=/root/.local/bin:$PATH
RUN python3 -m pip install --user awscliv2
RUN /root/.local/bin/awscliv2 -i

CMD ["/usr/local/bin/"]

# Install Ghost
RUN npm install -g [email protected]$GHOST_CLI_VERSION
RUN chown -R www-data:www-data $GHOST_HOME
RUN su -c 'ghost install $GHOST_VERSION --local --no-setup --db sqlite3' www-data
RUN su -c 'npm install sqlite3 --save' www-data

# Add static content generator
RUN npm install -g [email protected]$SITEMAP_GENERATOR_VERSION
RUN mkdir /static 

# Patch ghost
RUN mkdir -p /usr/local/etc/ghost/patches
COPY patches/ /usr/local/etc/ghost/patches/
COPY bin/* /usr/local/bin/

RUN /usr/local/bin/

# Copy ghost config
COPY data/config.json /var/www/ghost/current/config.production.json
  • As you can see from the above script it passes the Ghost version and Disqus site to the following script that then updated the disqus.patch file with the values. This is my improvement over the original GitHub so I do not need to update the version numbers every time I update Ghost.
# get args

echo ghost version $GHOST_VERSION
echo site domain $DISQUS_SITE

echo Replace text in disqus.patch
  • Then the following patch would be applied when the Dockerfile ran to use configured the values, GHOST_VERSION and DISQUS_SITE. This is essential for the patch to be applied to the installed Ghost blog. Note here I am using the default casper theme.
--- versions/GHOST_VERSION/content/themes/casper/post.hbs
+++ versions/GHOST_VERSION/content/themes/casper/post.hbs
@@ -69,11 +69,19 @@
-    {{!--
-    <section class="article-comments gh-canvas">
-        If you want to embed comments, this is a good place to paste your code!
-    </section>
-    --}}
+    <section class="article-comments gh-canvas">
+    <div id="disqus_thread"></div>
+    <script>
+    (function() { // DON'T EDIT BELOW THIS LINE
+    var d = document, s = d.createElement('script');
+    s.src = '';
+    s.setAttribute('data-timestamp', +new Date());
+    (d.head || d.body).appendChild(s);
+    })();
+    </script>
+    <noscript>Please enable JavaScript to view the <a href="">comments powered by Disqus.</a></noscript>
+    </section>
@@ -114,4 +120,4 @@
\ No newline at end of file

So I have all that code customised for my blog and I need to create the static files.

  • If this is the first time setup then from the root project run docker-compose up.
  • Go to and edit your brand new Ghost blog or import your backup content.
  • I would have generated the static files using docker-compose exec app /usr/local/bin/ but that comes later in my setup when I upload to S3.

In what you have seen so far there is still more configuration I could do and I will come back to this article if I do make other changes. In the next few articles I will show what I did to easily backup and update the static website with two separate scripts.