I often get the question: how do you manage your blog? Do you pay anything for hosting your blog? Do you have some sort of markdown interpreter? How about Search Engine Optimizations, can your blog posts be found online using Google? The short respective answers: Completely managed through a self-hosted Ghost instance, completely free, with rich editor and out of the box search engine optimizations.
So, how does it work? Let's start with a list of requirements:
- Running Ghost locally via Docker
- Setting up
ghost-static-page-generator
for creating static page content - Set up Github Pages repository to host your static HTML
- Optionally: Add CNAME record and update DNS records to host your blog on your custom domain
Running Ghost locally via Docker
After you've setup Docker, run Ghost locally with the following docker-compose.yml
, this also sets up a local mysql container for storing your blog posts:
version: '3'
services:
ghost:
container_name: ghost
image: ghost:latest
restart: always
ports:
- 2368:2368
volumes:
- ./content:/var/lib/ghost/content
environment:
url: http://localhost:2368
database__client: mysql
database__connection__host: db
database__connection__user: root
database__connection__password: superS3cretp@ssw0rd
database__connection__database: ghost
db:
container_name: ghost_mysql
image: mysql:8.4
command: mysqld --mysql-native-password=ON --authentication_policy=mysql_native_password
restart: always
environment:
MYSQL_ROOT_PASSWORD: superS3cretp@ssw0rd
volumes:
- ./data:/var/lib/mysql
Note: remember to change your database password to a strong unique password
With this file in-place, run the container with:
docker-compose up -d
Once the initial run is complete, your Ghost instance will be available at http://localhost:2368.
Set up ghost-static-site-generator
With Ghost running locally, you can convert your blog to static html with gssg
. This creates static html and resources for all the endpoints of your blog, which you can then host on a website. Static sites benefit from faster load times and enhanced security since they don't rely on server-side scripting, making your blog not only quick to access but also less vulnerable to web attacks.
To install gssg
, with Node.js installed on your local machine, globally install gssg
using:
npm install -g gssg
With gssg
installed, you can generate the static site with:
gssg --domain http://localhost:2368 --url https://blog.example.com --dest ./static
With the following parameters
--domain
this is the domain and port hosting your local Ghost instance--url
the external URL where your blog will be hosted (e.g., https://blog.example.com)--dest
the local path of your static website content
Push blog content to Github Pages
To make your blog accessible to the world, push your static HTML content to a GitHub repository configured with GitHub Pages. GitHub Pages offers a robust, free hosting solution that integrates seamlessly with your GitHub workflow. For most personal and project blogs, it provides a perfect balance between ease of use and functionality.
Follow the instructions below to setup your own GitHub repository with GitHub Pages:
- Create a repository named
your-github-username.github.io.
For example, mine is https://github.com/bart-jansen/bart-jansen.github.io - Push your static HTML content to this repository
- Your blog is now available at https://your-github-username.github.io
Add CNAME record to host your blog on your own custom domain
To personalize your blog's URL, you can configure a custom domain by adding a CNAME record. A CNAME record (Canonical Name) redirects visitors from your default GitHub domain to a domain name of your choosing. For instance, instead of your-github-username.github.io
, visitors could reach your blog via www.yourblogname.com
.
Follow instructions in the link above:
- Navigate to Settings -> Pages and configure your domain e.g.
bart.je
which will push aCNAME
file to root of your repository withbart.je
- Add the appropriate DNS records to your domain provider
- Optionally enforce HTTPS, using either your own SSL certificate, or by e.g. putting Cloudflare in between.