Skip to content

Instantly share code, notes, and snippets.

@remarcable
Last active January 30, 2023 14:50
Show Gist options
  • Save remarcable/1fc99065916937b50b9708189b9426f7 to your computer and use it in GitHub Desktop.
Save remarcable/1fc99065916937b50b9708189b9426f7 to your computer and use it in GitHub Desktop.
Setting up Netlify with Ghost in subdirectory on Digitalocean

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:

Steps

  1. 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.
  2. SSH into your droplet. In Ghost's config.production.json (you can find it in /var/www/ghost), update the url parameter with the final URL you desire. Make sure to add the https. I chose https://www.mental.garden/blog.
  3. 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 from 2369 to 2368.
  4. 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"}
  1. 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.
  2. You are done! The next steps are optional but recommended.
  3. 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.
  4. From Cloudflare's dashboard, click on "Workers" in the sidebar. Make sure you don't open one of your domains – workers are global.
  5. 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. Replace base and subdirectory 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);
  },
};
  1. 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/
  2. 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.
  3. Done 🙌

Add any questions you may have in the comments below. Good luck!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment