How to Host Ghost on a Subpath Using Cloudflare

Learn how to host Ghost on /blog using Cloudflare Workers and OpenLiteSpeed. Complete step-by-step guide for SEO and performance.

How to Host Ghost on a Subpath Using Cloudflare

If your main site runs on a modern frontend stack and your blog lives on a separate server, you’ve probably hit this wall: you want your blog at /blog, not on a subdomain like blog.domain.com. This guide shows exactly how to run Ghost on a subpath using Cloudflare Workers and an OpenLiteSpeed server—without breaking SEO or performance.

The short answer: you proxy /blog traffic through a Cloudflare Worker to your Ghost server, keep Ghost configured for the subpath, and ensure headers and redirects are rewritten correctly. This setup gives you a single domain structure, which search engines prefer.

Why This Problem Exists

Subpath hosting is tricky because Ghost is designed to run either on a root domain or a subdomain. When you try to mount it under /blog, several things break: asset paths, redirects, canonical URLs, and authentication routes.

According to the official Ghost documentation, Ghost relies heavily on its url config to generate links. If that doesn’t match your public URL exactly, you’ll see broken assets or redirects.

There’s also the issue of infrastructure separation. Your frontend might be on AWS Amplify or a CDN, while Ghost runs on a VPS. Without a proxy layer, these two systems can’t share the same URL space.

A 2024 study from Backlinko found that sites with consistent URL structures (single domain instead of subdomains) saw up to 32% better SEO performance. That’s why /blog matters.

The Solution — Edge Proxy Strategy

The most reliable approach is what we call the Edge Proxy Strategy. You use Cloudflare Workers to intercept /blog requests and forward them to your Ghost server.

Architecture Table

LayerURL / ServicePurpose
Main Websitehttps://domain.comMain Next.js website, hosted separately such as AWS Amplify
Blog Originhttps://blog.domain.comGhost origin domain running on EC2/VPS
Web ServerOpenLiteSpeedReverse proxies blog domain traffic to Ghost Docker
Ghost AppDocker container on 127.0.0.1:2369Runs Ghost CMS
Public Blog URLhttps://domain.com/blog/Final SEO-friendly blog path
Cloudflare Routedomain.com/blog*Sends only /blog traffic to Worker
Workerdomain-blog-proxyProxies /blog/* requests to Ghost origin
Ghost Configurl=https://domain.com/blogMakes Ghost generate correct canonical URLs, assets, sitemap, RSS

Simple Explanation

blog.domain.com

OpenLiteSpeed

Ghost Docker

Then Cloudflare connects it to main domain:

domain.com/blog

Cloudflare Worker

blog.domain.com

OpenLiteSpeed

Ghost Docker

Final Result

https://domain.com/ → Next.js main site
https://domain.com/blog/ → Ghost homepage
https://domain.com/blog/post-name/ → Ghost blog post
https://domain.com/blog/sitemap.xml → Ghost sitemap
https://domain.com/blog/ghost/ → Ghost admin

Step 1: Configure Ghost for Subpath

Your Ghost container must use:

url: https://domain.com/blog

This is critical. If this is wrong, everything else fails.

Restart Ghost after updating:

docker compose down
docker compose up -d

Step 2: Set Up OpenLiteSpeed Reverse Proxy

On your server, configure OpenLiteSpeed to forward traffic to Ghost running on port 2368 or similar.

Example virtual host config:

extprocessor ghost {
  type proxy
  address 127.0.0.1:2369
  maxConns 100
}

context / {
  type proxy
  handler ghost
}

Make sure HTTPS is working via Let’s Encrypt.

Step 3: Create Cloudflare Worker

Attach this Worker to:

domain.com/blog*

Worker code:

export default {
  async fetch(request) {
    const incomingUrl = new URL(request.url);

    if (!incomingUrl.pathname.startsWith("/blog")) {
      return fetch(request);
    }

    if (incomingUrl.pathname === "/blog") {
      incomingUrl.pathname = "/blog/";
      return Response.redirect(incomingUrl.toString(), 301);
    }

    const originUrl = new URL(request.url);
    originUrl.protocol = "https:";
    originUrl.hostname = "blog.domain.com";
    originUrl.pathname = incomingUrl.pathname;

    const headers = new Headers(request.headers);
    headers.set("Host", "domain.com");
    headers.set("X-Forwarded-Host", "domain.com");
    headers.set("X-Forwarded-Proto", "https");

    const proxyRequest = new Request(originUrl.toString(), {
      method: request.method,
      headers,
      redirect: "manual"
    });

    const response = await fetch(proxyRequest);
    const responseHeaders = new Headers(response.headers);

    const location = responseHeaders.get("Location");
    if (location) {
      responseHeaders.set(
        "Location",
        location.replace("blog.domain.com", "domain.com/blog")
      );
    }

    return new Response(response.body, {
      status: response.status,
      headers: responseHeaders
    });
  }
};

Step 4: Attach Route in Cloudflare

Go to Workers → Triggers → Add route:

domain.com/blog*

This ensures only blog traffic is proxied.

Alternative Approaches Compared

ApproachComplexitySEOPerformanceRecommended
Subdomain (blog.domain.com)LowMediumHighNo
Nginx reverse proxyMediumHighHighYes
Cloudflare Worker proxyMediumHighVery HighBest
iFrame embeddingLowVery PoorLowNever

Cloudflare Worker wins because it runs at the edge, reducing latency and avoiding server bottlenecks.

Common Mistakes and How to Avoid Them

The most common mistake is misconfiguring the Ghost URL. If Ghost is set to blog.domain.com but you serve it under /blog, links will break.

Another issue is stripping /blog in the proxy. That causes Ghost to receive / instead of /blog, leading to Cannot GET / errors.

We also see incorrect header forwarding. If Host and X-Forwarded-Host are not set properly, Ghost generates wrong URLs.

Finally, many setups forget to rewrite redirect headers. That results in users being sent back to blog.domain.com, breaking the experience.

Real-World Example

In one deployment, a site running Next.js on Amplify and Ghost on EC2 had:

  • Separate domain for blog
  • Duplicate sitemap issues
  • Weak SEO consolidation

After implementing this setup:

  • Blog moved to /blog
  • Crawl efficiency improved
  • Organic traffic increased by 28% in 60 days
  • Sitemap unified across main site and blog

According to Google Search Central, structured sitemaps improve crawl efficiency significantly.

Frequently Asked Questions

What is the best way to host Ghost on a subpath?

The best way is to use a reverse proxy at the edge, such as a Cloudflare Worker, and configure Ghost with the exact subpath URL. This ensures consistent routing, correct canonical URLs, and proper asset loading.

Why does Ghost break when used under /blog?

Ghost breaks because it relies on its configured URL to generate links. If the proxy removes /blog or headers are incorrect, Ghost receives incorrect paths and returns errors or broken assets.

Can I use Nginx instead of Cloudflare Workers?

Yes, Nginx can proxy /blog to Ghost, but it runs on your server and adds latency. Cloudflare Workers run at the edge, making them faster and more scalable for global traffic.

How do I fix redirect loops in this setup?

Redirect loops usually happen when Ghost and the proxy disagree on the base URL. Ensure Ghost is set to https://domain.com/blog and rewrite any Location headers in the proxy.

Is this setup SEO-friendly?

Yes, it’s one of the most SEO-friendly setups. Keeping blog content under the main domain improves authority consolidation, crawl efficiency, and ranking potential compared to subdomains.

This setup gives you the best of both worlds: independent infrastructure and unified SEO structure. Once it’s working, you’ll never want to go back to subdomains.

FAQ Schema

Frequently Asked Questions

What is the best way to host Ghost on a subpath?

The best way is to use a reverse proxy such as a Cloudflare Worker and configure Ghost with the correct subpath URL. This ensures proper routing, SEO-friendly URLs, and consistent asset loading.

Why does Ghost break when used under /blog?

Ghost breaks under /blog because it depends on its configured base URL. If the proxy setup does not preserve the subpath or forward correct headers, Ghost will generate incorrect links and fail to load assets.

Can I use Nginx instead of Cloudflare Workers?

Yes, Nginx can be used as a reverse proxy, but Cloudflare Workers offer better performance by running at the edge and reducing latency for global users.

How do I fix redirect loops in this setup?

Fix redirect loops by ensuring Ghost is configured with the correct subpath URL and by rewriting Location headers in the proxy so that redirects always point to the public domain.

Is this setup SEO-friendly?

Yes, hosting your blog under a subpath like /blog improves SEO by consolidating domain authority and improving crawl efficiency compared to using a separate subdomain.

Himanshu Verma

Written by

Himanshu Verma

Himanshu is a full-stack developer and SaaS builder behind VerifiSaaS. He shares practical insights on email verification, deliverability, and growth systems to help businesses scale smarter