So far everything has been fine-ish, and I absolutely applaud you guys for your work on Ghost, it’s simply amazing.
However, I have run into a few issues using your official docker deployment (caddy) when using an admin domain (dashboard.mywebsite.com).
When previewing a post, I get an error saying connection refused (iframe related)
This is an easy fix as I just added a rule to Caddy that allows this for my admin domain.
ActivityPub in general refuses to work (self hosted or not)
This is the log:
ghost-1 | [2025-08-14 11:15:09] ERROR Could not get webhook secret for ActivityPub FetchError: invalid json response body at https://mywebsite.com/.ghost/activitypub/v1/site reason: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
ghost-1 | [2025-08-14 11:15:09] ERROR No webhook secret found - cannot initialise
Is the problem that it’s not reaching the admin domain? Or am I mistaken in how this setup works?
I’ve read some of the suggestions on here (editing nginx config file,… not really doable since it’s Caddy).
Should I edit the caddy ActivityPub snippet to make this work? If so, I’m quite unfamiliar with Caddy, what should it look like?
1 - This is a security settings problem. In the security headers snippet (in caddy), remove the X-frame options setting, or set a more permissive value. (I’ve reported it, and the team has an issue open internally. Preview post and visit site do not work (Ghost 6.0 container) )
2 - If you haven’t already, can you bump Ghost to 6.0.3 (hopefully a fresh pull of the container will get you that). There was a missing redirect that was impacting specifically sites with separate admin domains, and it is fixed at 6.0.3.
Check your browser’s network console for errors also - any 401s?
I had very similar behavior (without docker) and fixed it with a redirect not-admin-site.tld/ghost/* over to actual-admin-site.tld/ghost/, but that should be fixed and working in 6.0.3.
Another possibility is that your containers aren’t talking to each other correctly
I did update to 6.03 and double checked in the container itself with the CLI that I am indeed running that.
I do see a few CORS errors in my network tab, which are probably the problem.
Access to XMLHttpRequest at 'https://mywebsite.com/.ghost/activitypub/v1/notifications/unread/count' from origin 'https://dashboard.mywebsite.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Will probably need to update something in one of the Caddy files
I’m not quite familiar with Caddy, I tried adding Access-Control-Allow-Origin "{$ADMIN_DOMAIN}" but the issue remains the same (I also recreated the containers with each change).. am I doing something wrong or overlooking something?
After a lot of messing around (turns out it was cached,…), I am now getting:
{"error":"Forbidden","code":"SITE_MISSING"}
Similar to @ppittman in his thread
Despite CORS not being an issue anymore, I do still encounter:
[2025-08-14 21:57:56] ERROR Could not get webhook secret for ActivityPub FetchError: invalid json response body at https://mywebsite.com/.ghost/activitypub/v1/site reason: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
[2025-08-14 21:57:56] ERROR No webhook secret found - cannot initialise
What’s happening on your ActivityPub container? Does it receive the requests properly?
The AP server has a concept of “sites” and should generally add a new site when it connects properly for the first time.
I have also seen cases where previous attempts failed, and a malformed site was put into the database, though this only happened in migrations from one server to another (with the webhook secrets getting lost on the way).
So if I check my AP docker logs, this is what’s inside:
21:57:54.534 INF activitypub: Message queue is disabled
21:57:54.794 INF activitypub: listening on :::8080, booted in 2885ms
21:58:15.323 INF activitypub: 'GET' 'mywebsite.com' 'https://mywebsite.com/.ghost/activitypub/v1/notifications/unread/count' 'e4f14fe6-911d-4f31-8a5c-42eef46eda98'
21:58:15.325 INF activitypub: KnexKvStore: Get key cachedJwks,mywebsite.com
21:58:15.416 INF activitypub: No site found for 'mywebsite.com'
21:58:15.417 INF activitypub: 'GET' 'mywebsite.com' 'https://mywebsite.com/.ghost/activitypub/v1/notifications/unread/count' 'e4f14fe6-911d-4f31-8a5c-42eef46eda98' 403 95ms
21:58:18.835 INF activitypub: 'GET' 'mywebsite.com' 'https://mywebsite.com/.ghost/activitypub/v1/notifications/unread/count' 'f1ba31a2-3462-428e-9715-02bddb8b0482'
So it does seem to get requests
I do also seem to see the admin dashboard occur in there at times:
22:13:12.419 INF activitypub: KnexKvStore: Get key cachedJwks,dashboard.mywebsite.com
22:13:12.673 INF activitypub: KnexKvStore: Set key cachedJwks,dashboard.mywebsite.com
I’ve just restarted the containers and I do notice that there’s no signs of AP getting any requests at startup (when the webhook secret can’t be initialised):
08:13:26.032 INF activitypub: Message queue is disabled
08:13:26.271 INF activitypub: listening on :::8080, booted in 3382ms
If I then go to the dashboard and look at the Network tab I do see some requests coming through:
08:13:26.032 INF activitypub: Message queue is disabled
08:13:26.271 INF activitypub: listening on :::8080, booted in 3382ms
08:14:47.773 INF activitypub: 'GET' 'mywebsite.com' 'https://mywebsite.com/.ghost/activitypub/v1/notifications/unread/count' 'fafa474c-7753-4d33-83f0-63f2976fa0f0'
08:14:47.774 INF activitypub: KnexKvStore: Get key cachedJwks,mywebsite.com
08:14:47.835 INF activitypub: No site found for 'mywebsite.com'
08:14:47.836 INF activitypub: 'GET' 'mywebsite.com' 'https://mywebsite.com/.ghost/activitypub/v1/notifications/unread/count' 'fafa474c-7753-4d33-83f0-63f2976fa0f0' 403 63ms
I did notice the request to AP happens at around the same time AP initialises, however when turning off Network in the dashboard, and back on, I get the same error (no secret found), implying it’s not a timing issue either.
Thank you @jannis (and @Cathy_Sarisky) for your help it led me in the right direction.
I saw the AP database existed but that all the tables were empty. This led me to check the error once again and I started doing some thinking. It mentioned an HTML response instead of JSON (that’s why it failed, it couldn’t parse it) – but when I visited the URL I did get JSON. So maybe it was cached?
Since this is the 2nd time a caching related issue came up I started looking at Cloudflare.
I removed them as a proxy, and miraculously it started working! I then turned back on the proxy and it’s still working..
Mess of a roller coaster but thank you all for your help!