How to self-host a blog site for free using Ghost

Planning on starting a blog site and wondering where to start? You can setup a blog site based on GhostCMS on a raspberry pi. Read on to find out.

How to self-host a blog site for free using Ghost
🎁
OFFER
At any time, if you feel stuck anywhere, you can use the Promo Code : BO-TSB-25 and reach out to the Sponsors for this blog, BinaryOats and get a flat discount of 25% OFF on setting up a ghostcms based blog for you.

Introduction

Some people like to write their thoughts for clarity of mind simply, others write to express ideas, some write to raise their voice, while some write to spread awareness. And then not to forget, there are those too, who write to spread misinformation or build a certain narrative that goes with their agenda. Whatever the reason, people have many reasons to write. Having a blog is the first step in this direction. So, in this blog post, you'll learn how you can set it up yourself for Free. Only downside is, /gif is not available as it is currently only available via the Ghost Pro. Be aware, I will keep referring GhostCMS as Ghost throughout this post. It means the same in this context.

GhostCMS

Ghost is an open-source headless CMS. It is a powerful CMS focused on professional publishing. Launched in 2013, it’s laser-focused on making life easy for bloggers, writers, and content creators who want their work to shine. Think of it as a slick, no-nonsense CMS built for storytelling, complete with a powerful editor, built-in SEO tools, and even features for running newsletters and paid memberships. Whether you’re setting up a personal blog or a full-blown online publication, Ghost has all the goodies to help you manage and grow your content without the technical headaches.

It is important to note that Ghost is completely Free for personal and commercial usage. It comes with an MIT licence and is written in JavaScript / Typescript.
But it would be unjust not to mention that the company also provides hosting for ghost-based sites. The cheapest plan starts at $9/month.

Now, let's understand, how you can set it up yourself, that too for free.

Setup

To setup GhostCMS, it is highly recemmended to use a non-root user for security reasons, like for setting up any other service. So, lets proceed ahead and setup a non-root user first.

Setup Non-Root User

So, to create a non-root user, say with username john, use the following cmd

adduser <USERNAME>

# e.g,
# adduser john

command to add new user in linux

and press enter a couple of times, and finally press y . You can obviously choose to enter further details. It is a matter of taste. However, I personally don't like entering information than necessary. I guess it is something I might have picked up living in Europe for some time - to care about your data privacy.

After that, add the user to the sudo user group using

usermod -aG sudo john

command to add user to the sudo group

Now, if you are connected to the machine using the SSH, it is also required to copy the SSH keys also to the new user's directory.

cp -r ~/.ssh /home/john
chown -R john:john /home/john

Command to copy SSH keys to new user workspace and assign proper permissions

This should be enough. Then simply exit the server, and login using the non-root user.

ssh john@<IP_ADDRESS>

command to securely connect to a machine ove SSH protocol

Now, the user has been set up, but what is important to note here is that you need to know the GID and UID of the user. You will need this information in the following step. To do that, use the following cmd

id <USERNAME>

# e.g,
# id john

command to check GID and UID of a user

Setup GhostCMS

Prepare Configuration file

Now, to setup Ghost, docker is the best choice, as it provides a secure environment to host the service, coupled with ease of convenience. Now, docker-compose also adds another layer of convenience to work with docker. You don't have to manually run a docker image, provide values in the command line, etc. You can use the docker-compose file, save it for future use and it will always pull the described docker images, run the application, and can restart in case of error or inactivity as well.

If you don't know how to setup Docker, no worries, check out the below mentioned blog post first and then come back here to continue.

How to setup Docker on Linux
Setting up Docker on a linux machine is pretty easy and can be done in less than 10 minutes. Read on to find out how.

At this point, you should already have docker and docker-compose installed. Let us proceed ahead then.

NOTE
Anything written in angle brackets <> , in the docker-config file below, is a variable. And anything written to the right of # is a comment.

To set up a blog site based on the GhostCMS, you can use the following docker compose template.

version: '3.1'

services:

  ghost:
    image: ghost:5-alpine
    restart: always
    user: <UID>:<GID>  # Replace with the non-root UID:GID

	  # e.g, if user UID and GID are 1000
	  # user: "1000:1000"
    ports:
      - <CUSTOM_PORT>:2368
    depends_on:
      - db
    environment:
      # DATABASE
      # ========
      database__client: mysql
      database__connection__host: db
      database__connection__user: <DATABASE_USERNAME>
      database__connection__password: <DATABASE_PASSWORD>
      database__connection__database: <DATABASE_NAME>
      url: <SITE_URL>

      # MAIL
      # ====
      mail__from: <SMTP_MAIL_FROM_ADDRESS>
      mail__transport: "SMTP"
      mail__options__host: <SMTP_HOST_NAME>
      mail__options__port: <SMTP_PORT_NUMBER>
      mail__options__auth__user: <SMTP_AUTH_USERNAME>
      mail__options__auth__pass: <SMTP_AUTH_PASSWORD>
    
    volumes:
      - <HOST_MACHINE_FILE_PATH>:/var/lib/ghost/content
      # or
      # - ghost:/var/lib/ghost/content
  db:
    image: mysql:8.0
    restart: always
    user: <UID>:<GID> 
    environment:
      MYSQL_DATABASE: <DATABASE_NAME>
      MYSQL_USER: <DATABASE_USERNAME>
      MYSQL_PASSWORD: <DATABASE_PASSWORD> 
      MYSQL_ROOT_PASSWORD: <DATABASE_ROOT_PASSWORD>
    volumes:
      - <HOST_MACHINE_FILE_PATH>:/var/lib/mysql
      # or
      # - db:/var/lib/mysql

volumes:
  ghost:
  db:

Docker-compose configuration file for setting up ghostcms based blog

As you can see, we used quite some variables here. These variables need to be replaced with their correct values.

  • UID and GID you have already discussed above.
  • Database variables like DATABASE_USERNAME , DATABASE_PASSWORD etc, needs to defined. For better security, use long random passwords which are hard to crack.
NOTE
Make sure to use the same values for all the DATABASE_ prefixed values in both the places, under ghost -> environment and under db -> environment.
  • SMTP variables like SMTP_MAIL_FROM_ADDRESS or any variable with the prefix SMTP_ is technically Not a requirement. But it is recommended if you're planning to allow users to signup on your site. It is only used to send the Sign-up emails or other account management related emails like account Login email. If you already have your email-server, you can use those credentials here, but if not, then you can use gmail account's SMTP credentials for sending emails. Note, this is not recommended.
  • Now, to persist the data, you would need some place to store. You've already defined the database credentials, but the above defined docker-compose configuration file will spin up a new database docker container, and save the data locally. You see, the line database__connection__host: db means, to use the database container which we're defining in the section below that. Now, you can also use some database hosted somewhere else, but then you need to change this line, specify something like database__connection__host: <HOSTED_DATABASE_HOST_URL>.
    Back to our use case, since we've used the docker container approach, we'll need to store somewhere locally.

    So, we've two options now :-
    1. Directly store in a docker volume, which is managed by docker. But I personally don't like this approach. Even though you'll save some effort here, but if your device gets corrupted or something bad happens, all your data would be lost. Meaning, all your blog posts, content everything will be lost forever. I would surely not want that. So, I use the second approach.

    2. Map your storage volume to some directory on your raspberry pi. This is why I've used the variable HOST_MACHINE_FILE_PATH to store content somewhere like in /home/john/ghostcms/data on your machine. Now, once you've the files somewhere locally, you can also setup a file synchronization service like syncthing to backup this data to your cloud or to another machine, whatever you choose.

Deploy config file

Once you've defined every variable, and the docker-compose file is ready, you can go ahead and start the deployment of all the services using this command

docker-compose -d up

The -d flag is used to run the command in a detached (background deamon) mode, meaning the docker containers will keep working after executing the command. If this flag is not provided, the docker-containers will stop as soon as the terminal is closed. In other words, the services run as long as the terminal is left running.

Now, your ghostcms based blog is running at the localhost at port number defined by the <CUSTOM_PORT> in the docker-compose file. But if it not accessible from the outside world. So, as the next step, you need to add the configuration in a reverse proxy of your choice. We already have the written another blog post on how to add configuration in nginx, which I personally find easiest to work with. I am also using Apache for some services in my homelab but nginx is undoubtedly the easiest to work with.

Using NGINX to redirect to multiple websites
Planning on serving multiple websites using a couple of devices? Wondering how to redirect the incoming URL requests to multiple devices on LAN using a reverse-proxy like NGINX? Read on to find more…

Finally, when everything is done, you can celebrate and start posting to your blog.

If you have any questions, opinions or feedback to give, please feel free to write in the comments below.