A quick follow-up to yesterday’s post about the issues I faced getting Ghost’s ActivityPub—Network—functionality up and running: I’m now trying with Ghost(Pro) on my normal domain, and I’m still running into problems.
This time, the issue is slightly different: Network is enabled in Ghost’s settings, but when I open the Network tab I get an “Account suspended” warning. Looking in the Web Inspector, I see a host of 403 errors in the console, and using RapidAPI I get the following error:
{"error":"Forbidden","code":"SITE_MISSING"}
My current theory is that this is happening because my site was previously hosted on WordPress, which had ActivityPub enabled. If that’s the case, this could be an issue for anyone migrating between platforms.
Here’s hoping Ghost support can sort this out next week.
I love Ghost, but I simply can’t get their ActivityPub functionality to work in a self-hosted configuration.
I have done extensive testing:
- using the New Install (i.e., Docker) option
- on both Digital Ocean and Vultr
- with this domain and fresh domain
- using self-hosted and Ghost’s own ActivityPub infrastructure
- using a Ghost admin domain at
site.tld/ghost and admin.site.tld
- proxying and not proxying using Cloudflare
Nothing works.
When using Ghost’s infrastructure, I receive Policy Violation errors. When I use my server’s own ActivityPub service at :8080 I get HTTP 403 errors. It’s a little disappointing.
However, when self-hosting, the native analytics with TinyBird worked as advertised and were really well presented, though not as in-depth as Plausible.
When not self-hosting I tried one of the fresh domains above with Ghost(Pro) and the ActivityPub functionality worked. It was marvellous.
I’m really hoping these issues are just early 6.0 bugs for self-hosters.
Some credit to Cathy Sarisky for helping the community.

After around six years dabbling with Ghost and static site builders I’ve migrated back to WordPress.
First impressions of the wp-admin panel were “meh”. It’s not really changed in the last few years and it’s really not as nice as Ghost’s admin panel. It does the job, though.
The Gutenberg editor, however, is amazing. It’s such a massive improvement—at least from memory—over the old WYSWYG editor.
To get things just so, I’ve had to install a few plugins:
-
Yoast SEO
-
Advanced Custom Fields
-
I’ve created an external_url field so that I can use it in the JSON feed 1.
-
JSON Feed (by Manton Reece and Daniel Jalkut)
-
Code Block Pro
-
Secure Passkeys
-
Various plugins to add Fediverse tags to the <head> element
-
ActivityPub
To get footnotes to render correctly in RSS readers—i.e., appear as pop-ups—I’ve added the below code to functions.php:
function clean_gutenberg_footnotes_for_rss($content) {
if (!is_feed()) return $content;
$refIndex = 1;
$uuidToIndex = [];
// Step 1: Replace <sup> references with numbered links and track mapping
$content = preg_replace_callback(
'/<sup data-fn="([^"]+)" class="fn">\s*<a[^>]*>(\d+)<\/a>\s*<\/sup>/i',
function ($matches) use (&$uuidToIndex, &$refIndex) {
$uuid = $matches[1];
if (!isset($uuidToIndex[$uuid])) {
$uuidToIndex[$uuid] = $refIndex++;
}
$n = $uuidToIndex[$uuid];
return "<sup id=\"fnr-{$uuid}\"><a href=\"#fn-{$uuid}\">{$n}</a></sup>";
},
$content
);
// Step 2: Rewrite footnote section and replace ↩ links
$content = preg_replace_callback(
'/<ol class="wp-block-footnotes">(.*?)<\/ol>/is',
function ($matches) use (&$uuidToIndex) {
$footnotes = $matches[1];
preg_match_all('/<li id="([^"]+)">(.*?)<\/li>/is', $footnotes, $liMatches, PREG_SET_ORDER);
$output = '<div class="footnotes"><ol>';
foreach ($liMatches as $li) {
$id = $li[1];
$rawText = $li[2];
$n = $uuidToIndex[$id] ?? '?';
// Replace ↩ <a> link with formatted Unicode arrow link
$fixedText = preg_replace(
'/<a[^>]+href="#' . preg_quote($id, '/') . '-link"[^>]*>.*?<\/a>/is',
'<a href="#fnr-' . $id . '" class="footnoteBackLink" title="Jump back to footnote ' . $n . ' in the text.">↩︎</a>',
$rawText
);
$output .= '<li id="fn-' . esc_attr($id) . '"><p>' . trim($fixedText) . '</p></li>';
}
$output .= '</ol></div>';
return $output;
},
$content
);
return $content;
}
add_filter('the_content', 'clean_gutenberg_footnotes_for_rss');