Running a professional blog for free

styxlab

Joost Jansky

Posted on November 15, 2020

Running a professional blog for free

Ever wanted to run a blog site with zero costs? This tutorial explains how to do this in minutes with Jamify! If you follow along with the instructions in this tutorial, you'll have your own zero-cost setup by the end of this article featuring professional class speed, availability and security.

Running a professional blog for free

If you ever deployed a blog or website to the public internet, you know that running a live site usually incurs operational costs. For example, a managed blog site hosted on Ghost.org starts at $29/month.

You can considerably cut down such expenses by using a self-hosted solution, but a publicly reachable server is not free. A self-hosted solution typically costs around $5/month. Even a relatively inexpensive solution that was described in the Ghost CMS on Hetzner Cloud tutorial here on Jamify.org cost you at least $3/month.

As Jamify sites are static sites they can be deployed to a global CDN and do not require traditional servers. CDN deployments are extremely cost efficient, therefore you can benefit from the free tiers of Netlify or other providers and run your live site at no costs on a global CDN.

However, up until recently, you still needed at least a self-hosted Ghost CMS installation on a public server. Why? Because not all images were included in your Gatsby bundle, so they had to be served from your Ghost CMS! That's why you had to make sure your CMS is publicly reachable and available 24/7, depleting all the cost benefits of the static site approach.

With the new Jamify plugin gatsby-rehype-inline-images you can now integrate all images into your static site bundle, so you do not need the CMS for serving images anymore. This opens up the possibility to deploy your blog from localhost for free.

Ghost CMS on localhost

Besides costs, being able to run your headless Ghost CMS on localhost has a couple of notable advantages:

  • Easier setup as all production concerns fall away.
  • No need to worry about security (firewalls, proxies, ports, authentication, SSL certificates, etc.).
  • You can build your Jamify website offline and achieve fast build times that are not limited by network bandwidth (unless your blog incorporates external images).

Of course, a local CMS installation also has some limitations and cannot cover all use cases:

  • Authoring articles with teams is not possible (no public access).
  • Member functions (e.g. newsletter subscription and distribution) cannot be used (no publicly available backend).

Even if you need a public Ghost CMS installation at some point in time, a localhost installation is still the number one choice in a lot of testing scenarios.

Local CMS install

Let's start with installing a Ghost CMS on your local machine. The following instructions have been tested on a Linux system running on Fedora, but should work on other Linux flavours too, including MacOS.

If you are using Windows it is recommended to install the Windows Subsystem for Linux (WSL 2) and use Ubuntu 20.04 LTS.

Prerequisites

To install Ghost locally make sure you install Node.js, the package manager yarn and the ghost-cli. Even if Node.js is already installed, check that you have a recent version:

$ node -v
v12.18.2
Enter fullscreen mode Exit fullscreen mode

Node comes bundled with the package manager npm. Make use of it right away and install yarn and the ghost-cli with it:

$ sudo npm -g install yarn ghost-cli@latest
Enter fullscreen mode Exit fullscreen mode

Install Ghost

With the needed tools available, you can now create a new directory and install Ghost CMS in it:

$ mkdir ghost-local
$ cd ghost-local
Enter fullscreen mode Exit fullscreen mode

Use the previously installed ghost-cli for performing the actual install:

[ghost-local]$ ghost install local
Enter fullscreen mode Exit fullscreen mode

It may take a minute to download and install all files. After a successful install, you can visit the CMS under http://localhost:2368/ghost/ and complete the setup process in three steps:

Running a professional blog for free

Running a professional blog for free

Running a professional blog for free

For a local install, you can safely enter a bogus email address and skip the staff user invite as you won't be able to work in teams anyway. After completing the final step, you should be brought to the Ghost Admin dashboard.

Create API keys

The initial setup is now complete. You can make further customizations in the admin interface, but this is not required at this point in time.

In other tutorials on Jamify.org you may read the recommendation to turn on headless mode. For a local installation this is not needed as the installation will never be available publicly, so you can skip this step.

In order to be able to connect to your Ghost instance with Jamify later, you need to generate a content API key. Go to Integrations -> Add custom integration

Running a professional blog for free

and click Create in order to generate a new key:

Running a professional blog for free

Starting and Stopping

The installation routine automatically starts the local Ghost server. You can stop it with the following command:

[ghost-local]$ ghost stop
Enter fullscreen mode Exit fullscreen mode

You will also have to re-start your server after every reboot:

[ghost-local]$ ghost start
Enter fullscreen mode Exit fullscreen mode

If you want to check whether or not Ghost is currently running you can use this handy command:

$ ghost ls
Enter fullscreen mode Exit fullscreen mode

Keep the current Ghost server running if you want to follow along with this tutorial.

Importing Content

If you are already running another Ghost instance, you may want to import your content to your local installation. The easiest way is to use the import/export functionality under the Labs section.

Unfortunately, images must be transferred manually. So, in addition to the above import/export for the textual content, copy all images in directory content/images/ from the source to the target Ghost instance.

Local Jamify install

With a local CMS install it also makes sense to generate your static site locally, in fact, you won't be able to build your site with a cloud provider because your localhost CMS is unreachable for them. Let's download the Jamify starter:

$ git clone https://github.com/styxlab/gatsby-starter-try-ghost.git jamify-starter
Enter fullscreen mode Exit fullscreen mode

and change into the work directory:

$ cd jamify-starter
Enter fullscreen mode Exit fullscreen mode

Adding Keys

The Jamify starter must be told to source in the CMS content from you Ghost CMS on localhost. For that, create a new file called .ghost.json in your work directory and copy the previously generated content API keys in it:

{
  "development": {
    "apiUrl": "http://localhost:2368",
    "contentApiKey": "2a087eea8fc3c9a3e7392625c0"
  },
  "production": {
    "apiUrl": "http://localhost:2368",
    "contentApiKey": "2a087eea8fc3c9a3e7392625c0"
  }
}

Enter fullscreen mode Exit fullscreen mode

You must replace the contentApiKey with your own!

Remove members plugin

The Jamify starter includes some plugins for convenience, one of which is the gatsby-theme-ghost-members plugin. As discussed earlier, the members plugin needs a public backend which currently must be a Ghost CMS, therefore the subscription flow won't work with a CMS on localhost. That's why you should remove this plugin:

[jamify-starter]$ yarn remove gatsby-theme-ghost-members
Enter fullscreen mode Exit fullscreen mode

and also exclude it in your gatsby-config.js:

// gatsby-config.js

plugins: [

    //{
    // resolve: `gatsby-theme-ghost-members`,
    //},

]
Enter fullscreen mode Exit fullscreen mode

Add plugin for inline images

While feature and all meta images are included in the static bundle by default, all inline images within posts or pages are only included if you add the new gatsby-rehype-inline-images plugin:

[jamify-starter]$ yarn add gatsby-rehype-inline-images
Enter fullscreen mode Exit fullscreen mode

This is a sub-plugin of the gatsby-transformer-rehype plugin and must be placed into your gatsby-config.js as follows:

// gatsby-config.js

plugins: [

    {
        resolve: `gatsby-transformer-rehype`,
        options: {
            filter: node => (
                node.internal.type === `GhostPost` ||
                node.internal.type === `GhostPage`
            ),
            plugins: [
                {
                    resolve: `gatsby-rehype-ghost-links`,
                },
                {
                    resolve: `gatsby-rehype-prismjs`,
                },
                {
                    resolve: `gatsby-rehype-inline-images`,
                },
            ],
        },
    },

]
Enter fullscreen mode Exit fullscreen mode

Including this plugin may result in longer build times as all inline images must be downloaded. However, as you are downloading them from localhost you are not limited by network bandwidth.

The gatsby-rehype-inline-images plugin also processes images, so they are lazy loaded and fade in with a nice blur-up effect known from Medium. See the plugin readme to learn more about the options this plugin provides.

Smoke test

You can now start your first test build with

[jamify-starter]$ yarn develop
Enter fullscreen mode Exit fullscreen mode

and see if the build succeeds. Check the results on http://localhost:8000/. Now, add a new article in your Ghost CMS on localhost and press the Publish button. After that re-build your project again with:

[jamify-starter]$ yarn develop
Enter fullscreen mode Exit fullscreen mode

and verify that the new article comes through:

Running a professional blog for free

Build your static site

While the development command is great for testing, you need to issue the build command to generate an optimized bundle that can be deployed to a CDN:

[jamify-starter]$ yarn build
Enter fullscreen mode Exit fullscreen mode

Check that your site looks as expected by starting the build server:

[jamify-starter]$ gatsby serve
Enter fullscreen mode Exit fullscreen mode

and visit your site at http://localhost:9000/.

Deploy to Netlify

Now its time to deploy your site to a global content delivery network (CDN). This step has been described in more detail in the getting started tutorial.

Here, I just repeat the simple steps. Once you have the Netlify CLI tool installed you can login

$ sudo npm -g install netlify-cli

[jamify-starter]$ netlify login
Enter fullscreen mode Exit fullscreen mode

and deploy the previously build bundle from the public/ folder.

[jamify-starter]$ netlify deploy --prod
Enter fullscreen mode Exit fullscreen mode

Answer the upcomimg questions as follows:

Running a professional blog for free

and you should see you site manually published on Netlify

Running a professional blog for free

under https://eager-golick-336605.netlify.app or another unique subdomain.

Running a professional blog for free

Although optional, many people want to deploy their blog on a custom domain. You can either purchase a new domain on Netlify or bring your own. This does not come for free and a custom domain name will cost you about $1,5/month.

Congrats! 🎉 Believe it or not, your site is now running on a flaring fast CDN with zero operational cost. Plus, your site is even SSL secured and enjoys all the Jamstack security benefits.

Continuous Deployment

In another tutorial article, I showed how you can setup a continuous deployment pipeline, where a content change in your CMS triggers a site re-build which is then automatically propagated to your live site on the global CDN.

This setup heavily relies on online cloud services: your CMS must have a public endpoint that triggers a webhook on Gatsby Cloud which deploys the build to Netlify. With a CMS on localhost, this setup won't work anymore.

Webhooks on localhost

With a neat webhook open-source project from Adnan Hajdarević you can create a similar pipeline on localhost too. There are different methods available for installing this Golang program, here I choose to download the the webhook-linux-amd64.tar.gz binary package, unpack the file and copy the executable in /usr/bin/ folder of my machine to make it globally available.

The webhook program consumes a hooks.json definition file and spins-up a server on localhost. We need to define two actions:

  • Build the jamify-starter with yarn build
  • Deploy the build package with netlify deploy --prod

which can be combined in one script file called build-and-deploy.sh that you should place in your work jamify-starter directory.

#!/bin/sh

yarn clean
yarn build
netlify deploy --prod
Enter fullscreen mode Exit fullscreen mode

Make this file executable with:

[jamify-starter]$ chmod +x build-and-deploy.sh
Enter fullscreen mode Exit fullscreen mode

You can now create the hooks.json in the same directory:

[
  {
    "id": "jamify-webhook",
    "execute-command": "./build-and-deploy.sh",
    "command-working-directory": "/home/styxlab/jamify-starter"
  }
]

Enter fullscreen mode Exit fullscreen mode

The working directory must be an absolute path, please change it to your own needs. You can now spin-up the webhook server:

[jamify-starter]$ webhook -hooks hooks.json -verbose -port 7000
Enter fullscreen mode Exit fullscreen mode

You can now test this new hook by triggering the webhook with

$ curl -X POST http://0.0.0.0:7000/hooks/jamify-webhook
Enter fullscreen mode Exit fullscreen mode

Connect to CMS

You can add this webhook easily to your CMS on localhost, so it get's triggered whenever you make changes to your content:

Running a professional blog for free

Running a professional blog for free

Test your pipeline

Let's make a simple content change. For this test, I change the title of the first post and also exchange the feature image with another one from Unsplash. Make sure to hit the Update button after making these changes.

Running a professional blog for free

After the build has completed, your live site should then be automatically updated with the new content changes.

Summary

If you do not need member functions and mostly write your articles yourself, the described setup may be exactly what you need for running an up-to-date, super-fast, SSL-secured, shell-proof public blog site with 99.99% uptime at zero costs 🥳.

While this article focuses on the operating costs of a live blog site, it is worth mentioning that this solution makes blogging not only more affordable, it also makes blogging more accessible : The install process is much simpler, so that it is feasible for people who feel discouraged by traditional self-hosting solutions.

Furthermore, taking a public CMS server out of the equation will certainly reduce complexity, ongoing maintenance efforts and let your mind put at easy: without a server, you cannot be hacked.

Do you want early access to Blogody, the brand new blogging platform that I am creating? Just sign-up on the new Blogody landing page and be among the first to get notified!


This post was originally published at jamify.org on July 15, 2020.

💖 💪 🙅 🚩
styxlab
Joost Jansky

Posted on November 15, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Running a professional blog for free
webdev Running a professional blog for free

November 15, 2020