Ghost 6 Upgrade: From Docker to the Fediverse

Exploring the upgrade to Ghost 6, from Docker challenges and database migrations to Fediverse integration, and why the release feels like a foundation for the future rather than a breakthrough today.

Ghost 6 Upgrade: From Docker to the Fediverse
Welcome to Ghost 6 (image form ghost.org)

Software upgrades often carry the promise of transformation. Ghost 6 positioned itself as a milestone release, introducing native ActivityPub support, deeper analytics through Tinybird, and a refreshed administrative experience. For independent publishers, these features suggested broader reach, better insight, and smoother day-to-day management.

The appeal was strong. ActivityPub federation meant that a Ghost blog could be followed directly from Mastodon or Threads, tapping into the growing Fediverse without depending on email or search engines. Tinybird integration promised a more sophisticated view of reader behavior. Combined with performance improvements and ongoing membership features, Ghost 6 looked like the next step forward.

This article explores what Ghost 6 promised, the realities of upgrading, and whether the new features live up to expectations.

The Allure of Ghost 6

The selling points of Ghost 6 were clear. For years, Ghost has been positioned as a publishing platform that puts creators in control, and this release appeared to reinforce that mission.

The headline feature was ActivityPub support. By connecting Ghost to the Fediverse, blog posts could appear directly in Mastodon feeds, Threads timelines, and other federated platforms. In theory, this was the answer to discoverability: a way for independent publishers to reach readers without relying solely on email lists or the whims of search engine algorithms. With more platforms adopting ActivityPub, it felt like a future-proof step toward decentralized distribution.

The Social Web Explained: How ActivityPub Powers the Fediverse
The Fediverse offers an alternative to big social platforms. Learn how ActivityPub powers it and why it matters now more than ever.

Learn about the Fediverse

Analytics was another major attraction. Through its new Tinybird integration, Ghost promised deeper insights into traffic and engagement. Publishers could expect real-time dashboards and richer event tracking. For anyone trying to understand audience behavior, this seemed like a significant upgrade.

Beyond these flagship features, Ghost 6 also promised a cleaner administrative experience and ongoing refinements to its membership tools. Combined, the release was presented as both a technical evolution and a shift in how publishers could grow and sustain their audience.

Is it “safe” to upgrade to Ghost 6.0?
This question is clogging my inbox, so here you go.

Cathy Sarisky, a well known Ghost expert in the community, discusses upgrade experiences.

With these promises in mind, the decision to upgrade felt obvious. The question was not whether Ghost 6 would be installed, but how quickly it could be put into production.

The Reality of the Upgrade

The upgrade to Ghost 6 was not a simple pull-and-restart. Each layer of the stack introduced complications, and what began as a routine version bump turned into a series of hard lessons.

A Custom Docker Compose Deployment

The official Ghost 6 guidance targeted users moving from ghost-cli to a clean Docker stack. Technodabbler was already running on Docker Compose, which meant the recommended compose file could not be dropped in as is. The practical approach was to start from Ghost’s compose, strip out services already present in the stack, and stitch the rest into the existing configuration. Using the include keyword made this manageable, but only after a careful read of every service, volume, and environment block.

A full Ghost 6 stack has 5 componants, Ghost itself, Activity Pub, Traffic Analytics, MySQL database and Caddy proxy.

Merging was the easy part. The real work was alignment. Services had to attach to the correct user-defined network, depends_on needed to reference existing service names, and healthchecks had to match the way containers were already supervised. Care also had to be taken with data volumes, since Ghost’s defaults could easily overwrite existing mounts. The environment variables required careful review as well, ensuring that database credentials and secrets matched the values already in use. In the end, the hybrid file ran cleanly, but only after a full analysis of Ghost’s compose and several small but critical changes to fit the production layout.

Migrating to MySQL 8

MariaDB had worked reliably for years, even though Ghost never officially supported it. The development team has often explained that, as a small project, they could only commit to maintaining one database system. For the most part, Ghost tolerated MariaDB without issue. That changed with Ghost 6, when the new ActivityPub feature introduced queries that simply would not run on MariaDB.

At first glance, the solution seemed simple: migrate to MySQL 8, the database Ghost was designed for. In practice, the process uncovered subtle but significant differences between the two systems. Dumps from MariaDB included schema definitions that MySQL rejected. Default values were set on certain type of columns allowed MariaDB but not on MySQL.

⚠️
ERROR 1101 (42000) at line 28573: BLOB, TEXT, GEOMETRY or JSON column 'extra' can't have a default value

The only reliable strategy was to export the database then clean the resulting SQL dump manually before importing into MySQL 8. It was a tedious step, but once complete, Ghost 6 ran smoothly. The experience made clear that while MariaDB had been an acceptable workaround in the past, ActivityPub drew a firm line: Ghost now required MySQL.

Wrestling with Caddy and Redirects

Ghost 6 now runs three separate services: the main blog, the analytics endpoint, and the ActivityPub service. In Docker, each one listens on its own port, but Ghost expects them to be available under the same domain at different paths. A reverse proxy is required to bridge this gap. Cloudflare can handle TLS termination and redirects, but it cannot rewrite paths. That made Caddy essential for routing requests to the right backend service.

ActivityPub requests such as / .ghost/activitypub/, /.well-known/webfinger, and /.well-known/nodeinfo had to be forwarded to the ActivityPub container. Analytics endpoints, accessed through paths like /.ghost/analytics/, also needed to be rewritten before they reached their backend service. Without Caddy handling these routes, Ghost’s components could not function together under a single domain.

Technodabbler's network setup, with CloudFlare in front.

With routing in place, the second issue surfaced: the infamous infinite redirect between Cloudflare and Caddy. Cloudflare terminated TLS at the edge and forwarded plain HTTP traffic, while Ghost enforced HTTPS based on its configured URL. Because Caddy defaulted to sending X-Forwarded-Proto: http, Ghost assumed the connection was insecure and tried to redirect back to HTTPS. That redirect hit Cloudflare, which sent it back to Caddy, and the loop continued endlessly.

How Can Cloudflare Improve Your Website’s Speed & Security?
Last year, the development team for Ghost blog announced a partnership with Cloudflare. The goal was to improve the Ghost(Pro) infrastructure, making it faster and more secure. With a little tinkering, Cloudflare can be used with any Ghost blog. Technodabbler received this upgrade a couple of days ago. But

Cloudflare accelerates and protects the Technodabbler site.

The solution was to commit fully to SSL across the entire chain. Caddy was configured with internal certificates and treated every connection as HTTPS, while Cloudflare’s tunnel was updated to connect securely using the correct SNI for technodabbler.com. This ensured that Ghost always saw requests as secure, breaking the loop cleanly. In the end, running end-to-end TLS was the only approach that made sense, simplifying the setup and avoiding fragile header rewrites.

Deploying Tinybird Analytics

Another headline feature of Ghost 6 was its new analytics system, built on Tinybird. On paper, the integration promised richer insights and real-time dashboards. In practice, enabling it meant introducing several new Docker components and wiring them into the existing stack. The additional services made the deployment more complex and fragile, with more containers to supervise and more moving parts that could fail.

The real disappointment came after it was running. Despite being set up correctly, Tinybird reported a quota error within a day, even while no dashboards were in use. Quotas were supposed to apply only to interactive analytics queries, not passive data collection, which made the error all the more confusing. Worse, the data it provided did not go beyond what was already available through Plausible, which is the platform used by Technodabbler. And event without the Tinybird-powered analytics, newsletter performance and membership analytics were still available through Ghost itself, just as before.

The TinyBird limits came pretty quickly, and the upsell.

After some trial, it became clear that a Tinybird-powered analytics solution did not offer meaningful value for a small site already running Plausible. Economically, maintaining two analytics systems made little sense, and the free tier quotas were easy to exhaust. For larger sites, or professionally hosted Ghost deployments such as those on ghost.org or magicpages.co, the approach is attractive, since the pipeline can run on a larger Tinybird instance with paid capacity.

Making the Fediverse Work

The first challenge was simply proving that Ghost’s ActivityPub integration was working at all. Early tests from Mastodon resulted in repeated 404 errors when trying to follow the blog. Debugging meant inspecting the endpoints manually, checking .well-known/webfinger, the actor profile, and the outbox to confirm they responded correctly. The culprit turned out to be a conflict between the blog’s canonical domain and its redirect. The ActivityPub address was @[email protected], but the site defaulted to www.technodabbler.com. Since technodabbler.com was only set up as a redirect, federation requests were failing. The only reliable fix was to flip the configuration: make technodabbler.com the default domain, and set www.technodabbler.com as the redirect. Once this was done, Mastodon stopped returning 404 errors and the account could be followed.

Searching on Mastodon while dealing with configuration issues will result in a 404 error.

With the plumbing in place, Ghost began federating content through its outbox. But the outbox only contained posts created after ActivityPub was enabled. Existing articles never appeared, and the only workaround was to unpublish and republish them, which was impractical for a large archive. Even for new content, distribution depended on already having followers on the receiving server. Without someone following from a node like mastodon.social, posts would never propagate there. Federation quickly revealed a chicken-and-egg problem: visibility required followers, but followers required visibility.

Once configured, Technodabbler can easily be found on Mastodon with the proper address.WelcomWelW

When posts did deliver, results were mixed. The first Note never appeared on Mastodon until a second one was published, and Threads federation was still only partially deployed. While the setup confirmed that Ghost could technically federate into the Fediverse, it was far from frictionless. For a site that already had a Mastodon account and used Postiz to cross-post announcements, native ActivityPub support added little beyond the novelty of having a followable blog handle.

Was It Worth It?

Upgrading to Ghost 6 was an interesting journey. The flagship features, Fediverse integration and a Tinybird-powered analytics solution, both showed promise but did not add much value for a smaller independent site already running its own tools. For now, federation feels limited, and the analytics are better suited to larger deployments.

That said, the upgrade left the platform in a stronger place. Migrating to MySQL 8, consolidating everything under SSL, and refining the Docker deployment all improved the overall setup. Day-to-day administration feels smoother, and Ghost continues to be a solid foundation. The Fediverse support in particular is only at the beginning, and as the ecosystem matures, it could become a powerful way for independent publishers to reach new audiences.

In the end, Ghost 6 was less about immediate gains and more about preparing for what comes next.

💡
Have you tried upgrading to Ghost 6 yet? Share your experience in the comments, especially if you experimented with the Fediverse or Tinybird-powered analytics. If you found this article useful, you might also enjoy our coverage of the challenges of setting up a newsletter, which looks at the legal and practical side of reaching your audience. Want more hands-on explorations of technology delivered straight to your inbox? Subscribe to the Technodabbler mailing list and never miss a post.