How to make Ghost and Netlify work with /blog (hint: Cloudflare Workers)
Ghost is a really good CMS, however, using ghost with /blog
rather than subdomain is quite a hassle. Even in their pricing page, it is mentioned as “Supporting this setup is non-trivial”.
“It’s also possible to run sites on a subdirectory, like
example.com/blog
, however this requires customers to run their own self-hosted reverse proxy with a custom configuration. Supporting this setup is non-trivial”
Ghost
Why would someone prefer example.com/blog
rather than blog.example.com
though?
The answer is SEO.
SEO
Google will treat both subdomain and subdirectory equally. This seems like a good thing, but it’s not. All the hard work you did writing blogs, it only increases your blog.example.com
's ranking. If your blog was likeexample.com/blog
your landing page would also get that bump resulting in more leads!
If you have bought your domain from Netlify good luck! We’ll be explaining how you can achieve /blog
while using Netlify and Ghost. Firstly, you’d need to change your DNS provider to Cloudflare where you can have custom rules.
DNS
Initially, move your domain to Cloudflare. There are good posts explaining this process. To put it simply add the following DNS records.
A example.com 104.198.14.52
CNAME some-text-provided-by.netlify.com
Normally, it is recommended to only use DNS from Cloudflare but not the CDN itself. Netlify has it’s own CDN and cache invalidation. These are really important features of Netlify, but to make this setup work, we’d need to used Cloudflare as a reverse proxy.
Enable orange cloud for both of the records you added.
Setup Blog
If you don’t have a blog yet, follow the official guidelines. Get a blog ready. Most likely you’ll have a myblog.ghost.org
or blog.example.com
. Both are fine. Make sure it works.
The problem we’ll face is, how do we redirect example.com/blog
to myblog.ghost.com
. You’ll need a reverse proxy. Netlify used to handle all those annoying bits and it’s not customizable. You have two options, (1) have a custom reverse proxy server, make sure the DNS point to it, then you point it back to Netlify (2) Use Cloudflare Workers as a reverse proxy.
Note: If you are wondering if redirects would work, the answer is they won’t. Search engine crawlers understand redirect and give the SEO ranking to the destination URL.
Cloudflare Workers
Go to Cloudflare Dashboard — Workers — Manage Workers — Create a Worker
Add the following code
// keep track of all our blog endpoints hereconst myBlog = { hostname: "blog.example.com", // TODO change this to your blog domain targetSubdirectory: "/blog", assetsPathnames: ["/public/","/content/", "/assets/"]}async function handleRequest(request) { // returns an empty string or a path if one exists const formatPath = (url) => { const pruned = url.pathname.split("/").filter(part => part) return pruned && pruned.length > 1 ? `${pruned.join("/")}` : "" } const parsedUrl = new URL(request.url) const requestMatches = match => new RegExp(match).test(parsedUrl.pathname)
// if its blog html, get it if (requestMatches(myBlog.targetSubdirectory)) { console.log("this is a request for a blog document", parsedUrl.pathname) const targetPath = formatPath(parsedUrl) return fetch(`https://${myBlog.hostname}/${targetPath}`) } // if its blog assets, get them if (myBlog.assetsPathnames.some(requestMatches)) { console.log("this is a request for blog assets", parsedUrl.pathname) const assetUrl = request.url.replace(parsedUrl.hostname, myBlog.hostname); return fetch(assetUrl) } console.log("this is a request to my root domain", parsedUrl.host, parsedUrl.pathname); // if its not a request blog related stuff, do nothing return fetch(request)}addEventListener("fetch", event => { event.respondWith(handleRequest(event.request))})
The code is self-explanatory. Basically, if the path is myBlog.hostname
, it acts as a reverse proxy and fetches example.com/blog
.
The other thing it does is fetch the static content from the /blog
path. By default, the ghost should have the following paths for static content.
assetsPathnames: [“/public/”,”/content/”, “/assets/”]
Deploy the code. Done.
Just kidding. This is a ‘how do I get around X” blog post, did you expect it to be easy?
Go back to “Add route” button at Cloudflare Workers page and add the following.
- *example.com/blog*
- *example.com/content*
- *example.com/public*
- *example.com/assets*
Last Touches
You need to make sure your ghost blog link works with /blog
. To do that, change the @site.url argument from blog.example.com
to blog.example.com/blog
.
If you are using Ghost Pro, you might need to change the routes.yaml
to something like
routes:
/signup/: /blog/members/signup
/signin/: /blog/members/signin
/account/: /blog/members/accountcollections:
/:
permalink: /blog/post/{slug}/
template: index
/blog/:
permalink: /blog/post/{slug}/
template: index
filter: primary_tag:blogtaxonomies:
tag: /blog/tag/{slug}/
author: /blog/author/{slug}/
Now you have a Ghost blog using Netlify and Cloudflare. Good job.
🎉 Edgecase 🎊
- You can’t use Netlify CDN. Cloudflare CDN is good or even better. You might need to configure caching rules to make your landing page and blog faster.
- Netlify invalidates cache when you do
git push
. You won’t have this ability out of the box anymore. You can use Github Actions to get the same functionality or you can use a Workflow Automation tool like Zappier to achieve this. - Rather than Netlify SSL, you can use Cloudflare SSL. Select “Full” in Cloudflare SSL Tab.
- You won’t be able to use
blog.html
,content.html
,public.html
,assets.html
in Netlify anymore. You have overwritten those paths. If you have any, delete or rename them. - Cloudflare is fast enough. You won’t have any performance issues. Sidenote; Ghost Pro originally uses Cloudflare as CDN.
Lastly, as developers, we want everything to be easy. Tools like Netlify and Ghost gives us out the box solutions. However, once in a while you have generic use cases like this — which they have no good way of solving — you spend hours, days, and even sometimes weeks trying to figure it out. Stop cursing around. You literally deployed a custom blog and static webpage in mere hours! Be grateful for all the tools we have. You did great! Be happy.
If you enjoyed this post, you can follow me on Twitter or reach out to me on thellimist.com.