I didn't want to host ghost on a subdomain like blog.<domain>
. Instead, I wanted it under a subdirectory like /blog
.
On this page, I want to describe the steps you need to take to do just that with the following stack:
- Main landing page on Netlify (https://www.mental.garden)
- Ghost is hosted on Digitalocean.
- DNS is manged by Cloudflare
- Install ghost on a new Digitalocean droplet using these instructions. Choose a (temporary) subdomain for ghost and add it to Cloudflare or your DNS. I chose https://my.mental.garden.
- SSH into your droplet. In Ghost's
config.production.json
(you can find it in/var/www/ghost
), update theurl
parameter with the final URL you desire. Make sure to add thehttps
. I chose https://www.mental.garden/blog. - Run
ghost restart
. If this doesn't work, there might be a mismatch between the port Ghost uses and the one used by Nginx. I had to update the port in the config from2369
to2368
. - In your landing page repository, add a
netlify.toml
with the following contents. If you are using Next.js put it in the root folder instead of in/public
. Putting it in/public
broke my build. Replace the values with your own URL, commit, and deploy.
[[redirects]]
from = "/blog/*"
to = "https://my.mental.garden/blog/:splat"
status = 200
force = true
headers = {X-Forwarded-Host = "www.mental.garden"}
[[redirects]]
from = "/blog"
to = "https://my.mental.garden/blog/"
status = 200
force = true
headers = {X-Forwarded-Host = "www.mental.garden"}
- If you use Cloudflare, go to the domain's DNS settings. Enable the Cloudflare proxy for the domain that points to your landing page (something like
mentalgarden.netlify.app
). This wasn't necessary before becaues Netlify has its own CDN, but because of the redirect we created above, it probably doesn't cache/blog
. This reduces the load on the Ghost droplet. Also enable this for the subdomain where your blog lives. - You are done! The next steps are optional but recommended.
- I needed to create redirects from the subdomain to the new URL cecause I've already used the subdomain before. If you create a simple redirect, Netlify's proxy redirect doesn't work properly anymore. So we need to be a bit cleverer. I've used a Cloudflare worker for this.
- From Cloudflare's dashboard, click on "Workers" in the sidebar. Make sure you don't open one of your domains – workers are global.
- Create a new worker by clicking on "Create a Service". It doesn't matter which template you choose. Once created, click on "Quick Edit" to update the code. Replace it with the following script. This will redirect all requests that don't have the correct
x-forwarded-host
header to the new URL. Replacebase
andsubdirectory
with your own values. When you're done, click on "Save and deploy".
export default {
async fetch(request) {
const protocol = "https://";
const base = 'www.mental.garden';
const subdirectory = "/blog";
const statusCode = 301;
const url = new URL(request.url);
const { pathname, search } = url;
const updatedPathName = pathname === subdirectory ? "" : pathname;
const destinationURL = `${protocol}${base}${subdirectory}${updatedPathName}${search}`;
if (request.headers.get("x-forwarded-host") !== base) {
return Response.redirect(destinationURL, statusCode);
}
return fetch(request);
},
};
- Go back to the worker overview page and click on the "Triggers" tab. Add two new Routes (replace the URL with your own). Select your domain as the zone. Make sure to add the
*
.- my.mental.garden/blog/
- my.mental.garden/
- Follow the manual verification steps on "Validating your configuration" from this guide. The steps with the
x-ghost*
headers only seem to apply to hosting on ghost.org hosting. - Done 🙌
Add any questions you may have in the comments below. Good luck!