Help troubleshooting hosted ActivityPub redirect issues with self-hosted Docker + Cloudflare setup

If anyone self-hosting Ghost with Docker + Cloudflare (or Nginx reverse proxy) has gotten ActivityPub working using the hosted instance at ap.ghost.org, I’d really appreciate help troubleshooting my redirects!

I’m running ghost:6-alpine on Fly, behind Cloudflare. I am redirecting traffic successfully to ap.ghost.org, but still getting 403 forbidden errors for some routes, and I have the dreaded webhook secret error in my logs.

I have read all the forum posts I can find (thank you @Cathy_Sarisky and @jannis for sharing your wisdom so generously!), and I’m still stuck.

I think it’s a SITE_MISSING or ROLE_MISSING error perhaps? I wonder whether I had a malformed redirect, and there’s now a bad record in the ap.ghost.org DB for my site…

I also have an Nginx reverse proxy (not currently what my site is accessible through; it’s just a backup for Cloudflare, as a firewall for bot traffic). I tried doing the redirect through that. As far as I could tell the redirect was successful (the activitypub routes no longer hit the origin server), however no luck there either. I suspect this may be a CORS issue, since the proxy isn’t what the domain is pointing to.

Other things I’ve tried, that I’ve seen suggested various places:

  • hard reloading the page
  • using a different browser
  • restarting ghost
  • redirecting /ghost/activitypub/* rather than /.ghost/activitypub/*
  • toggling the Network on and off in the admin panel
  • putting Cloudflare in development mode
  • purging Cloudflare cache

Any pointers on how to debug this would be greatly appreciated!

2 Likes

For anyone else with the same issue, I have made some progress.

I: Nginx Reverse Proxy Success

I successfully got my Nginx reverse proxy redirecting AP traffic for a staging site, by setting the Ghost URL for the staging site to the proxy URL to get around CORS errors, and then turning off the Network features in the settings, rebooting, turning it back on, and rebooting again.

So, I have a AP working if I wasn’t hiding behind Cloudflare. But I’m not sure my proxy is robust enough on its own. And I can’t use the proxy just for AP because of the CORS errors when the Ghost url doesn’t match where the site is being accessed from.

II: Cloudflare cross-origin redirect header woes

I am fairly sure that what’s going on with Cloudflare has to do with headers being stripped from cross-origin redirects. I noticed that in some/all cases, when I inspect in the network tab, the original request to ActivityPub routes on the origin (which is a 301 permanent redirect) has an Authorization header, or a Cookie, that isn’t present on the redirected request to ap.ghost.org (which returns 403 Forbidden or 401 Unauthorized). Copy-an-pasting the Authorization header from the original request and resending turns the 403 to a 401 error.)

I’d like to use an “Origin Rule”, since that seems to be what I’m looking for, but that’s only available on Enterprise plans. I tried switching from a “Redirect Rule”, to a “URI Rewrite Rule”, to 3 “Page Rules”, but none of them have control over whether headers are stripped.

If anyone knows how to go about this, let me know!

I suspect that the fact that the Nginx version proxies traffic in the background, while still appearing to be the origin server, and Cloudflare redirects it, so requests are made to ap.ghost.org from the frontend, might be part of the problem.

The only idea I’ve had: set-up a route on my proxy as a passthru, point a subdomain/subdirectory of my origin DNS at that proxy route, and then redirect AP traffic to there from cloudflare (so the headers aren’t stripped out, since it would be same orgin), and then proxy it from there to ap.ghost.org, while keeping my site behind Cloudflare. This seems gross, so I hope someone has a better idea :slight_smile:

Update: solved by switching off Cloudflare to Nginx reverse proxy (without the various funky subdomain tricks I had tried), and updating my nginx.conf to include auth header and cache settings: