The Netlify CMS project was built with the Netlify platform in mind. How can we host it ourselves as the ultimate headless blog CMS?
Joey Miller • Last updated May 04, 2023
Netlify CMS is a headless CMS that makes it easy to write and edit content (e.g. markdown files) stored in a Git repository. It is easy to configure - you only need to update a YAML config file. It is a great choice when wanting to add content to any site built with a static site generator such as Next.js
, Gatsby
, Hugo
, etc.
As the project name suggests, the project was built with the Netlify platform in mind. Hosting Netlify CMS without Netlify (i.e. with AWS) means you cannot use their Netify Identification Service to authenticate with your git repository providers, such as Github or Gitlab. This means we need to host our own external OAuth server to use Netlify CMS.
To simplify the process, I developed a single Docker image that provides both a standalone Netify CMS installation and an OAuth server.
In this post, I will be assuming that you are connecting Netlify CMS to a GitHub repo.
To get started create a docker-compose.yml
file with the following:
version: '3'
services:
netlify-cms:
# headless netlify cms service on port 80
image: itsmejoeeey/docker-netlify-cms-standalone:latest
restart: always
environment:
- ORIGIN=<your root url>
- OAUTH_CLIENT_ID=<your github client id>
- OAUTH_CLIENT_SECRET=<your gitlab client secret>
volumes:
- ./config.yml:/app/config.yml
When authenticating with Github, create your OAuth secrets by going to Settings > Developer settings > OAuth Apps
. Create a 'New OAuth App' with:
Homepage URL
being <ORIGIN>
Authorization callback URL
being <ORIGIN>/callback
To the same directory as the docker-compose.yml
file, save this example config.yml
file making sure to update:
repo
, branch
to match an existing Github repository you have access to. i.e.: repo: itsmejoeeey/test-blog-content
branch: main
base_url
to match the <ORIGIN>
environment variable you set above. i.e.: base_url: https://cms.example.com
From the same directory as the docker-compose.yml
file, start the container with:
docker-compose up -d
For more detailed setup instructions, view the README.
My default example config.yml
file organizes the repo as follows.
├── posts
│ └── <year>
│ └── <month>
│ └── example_post.md
└── static
└── uploads
└── document.pdf
└── media
└── blog
└── <year>
└── <month>
└── example_post
└── image_1.png
└── image_2.png
When you use Netlify CMS to create a post, the markdown files will be stored under posts
.
Blog media such as images for a single post are grouped (by markdown filename) and stored in a similar structure under static/media
.
I chose to keep the static media (such as documents and blog post images) separate from the markdown files so that they could be easily hosted outside of Git if necessary at a later date.
While this structure is great for my needs, it won't be perfect for everyone. Netlify CMS is extremely flexible and configurable, so you'll be able to modify this to meet your needs in no time.
This blog you are reading is made with Netlify CMS + Gatsby (the React-based static site generator). Gatsby is used to host the blog markdown files as a navigable website.
The Gatsby starter blog project is a good place to start, but some modifications are necessary for it to be usable with Netlify CMS as we set up earlier.
First, we need to clone the starter project and install the necessary dependencies:
git clone [email protected]:gatsbyjs/gatsby-starter-blog.git
cd ./gatsby-starter-blog
npm install
rm ./content # delete the old content
Then we need to install the gatsby-source-git
plugin, as this will pull the markdown files from our blog content repository into the Gatsby graph.
npm install gatsby-source-git
And configure the plugin in gatsby-config.js
by replacing:
{
resolve: `gatsby-source-filesystem`,
options: {
path: `${__dirname}/content/blog`,
name: `blog`,
},
},
with:
{
resolve: "gatsby-source-git",
options: {
name: "blog-content",
remote: `https://<your github username>:<your github token>@github.com/itsmejoeeey/joeeey-site-blog-content.git`,
branch: "master",
patterns: [`posts/**`, `static/media/**`],
},
},
Don't forget to insert your GitHub credentials. Go to Settings > Developer settings > Personal access tokens > Fine-grained tokens
and create a token with the Contents
and Metadata
repository permissions enabled for your blog content repo.
We are now ready to start the development server with npm run develop
. Navigate to localhost:8000
and you will see the blog posts in your repo listed on the root page.
This is a basic starting point - numerous markdown fields from my Netlify CMS example config file are unused (such as cover
, tags
, etc).
The gatsby-starter-netlify-cms
project achieves a similar outcome and is worth a look. It has some additional features like generating tag pages automatically. Getting it up and running is out-of-scope for this post, as additional modifications would be necessary; we are now hosting Netlify CMS and our blog content repository externally (rather than having it all self-contained in the Gatsby repo).
Tags
If you found this post helpful, please share it around: