ActivityPub not loading with non-public admin URL

Is it possible to use ActivityPub in the following scenario?

  • Self-hosted Ghost, Public ActivityPub

  • Separate admin URL: admin.domain[.]com is the admin URL, public URL is www.domain[.]com

  • Admin URL is not publicly available - no DNS records published for admin.domain[.]com

  • location ~ /ghost/api/admin/site is not limited to specific internal IPs in nginx reverse proxy

  • location ~ /ghost/ is limited to specific internal IPs in nginx reverse proxy

  • These blocks have been added

I have this set up configured to limit the attack surface of my blog. When I configure my nginx reverse proxy to allow access to www.domain[.]com/ghost/api/admin/site/, I get an infinite number of redirects if I’m internal and the URL bar reflects admin.domain[.]com/ghost/api/admin/site. If I’m external the URL bar reflects admin.domain[.]com/ghost/api/admin/site and it can’t be found, obviously because admin.domain[.]com is not published.

Just wondering if this scenario / behavior has been accounted for / should be working properly / is expected behavior. Thanks!

Ghost’s API needs to be publicly available on the admin domain. The front-end app doesn’t serve any API requests so {frontend}/ghost/* will be redirected to {admin}/ghost/*. You may be able to get away with only making certain endpoints available publicly on the admin domain but you’ll still need DNS records for it.

1 Like

Thanks Kevin! Any chance there’s a list of the required public endpoints?

It very much depends on what you’re doing with the site. Ghost generally expects the API to be public as the admin panel, scheduling, comments moderation, integrations, etc are all built around the API.

You may be able to get away with just exposing /ghost/api/admin/site/ initially but you may find other things break later on. If you limit what’s public then I’d pay attention to the logs to see what’s being requested.

Just using it as a simple blog really - no subscribers, no comments. Would something like the following work and allow ActivityPub to function properly?

  • Make {admin}/ghost/api/* publicly available
  • Restrict access to {admin}/ghost/* to internal IPs only

Just interested in reducing the attack surface of the blog really. My understanding was that the support for the separate admin URL was intended for these types of restrictions. I wouldn’t want to open the publishing API endpoint up to the outside world, for instance (even if proper authentication is needed to perform it), if it wasn’t necessary.

Your best bet is to try and see, I don’t have full details to hand for what is/isn’t required for ActivityPub to fully function but I do think it’s just the /ghost/api/admin/site/ endpoint.

My understanding was that the support for the separate admin URL was intended for these types of restrictions

Support for a separate admin URL is mainly there to provide additional protection from browser cross-origin security. If front-end and admin are both on the same domain then the attack surface for staff user privilege escalation is higher as you don’t get the extra cross-origin security for free.

If you’re restricting public access to the API then doing it via front-end domain or back-end domain doesn’t make much difference other than possibly making the blocking configuration a bit simpler.

FWIW, there are many tens of thousands of Ghost sites with publicly accessible APIs that have been public for many years with no issue. We take security of the API very seriously :slight_smile:

1 Like

Gotcha. Thanks Kevin! I appreciate your time here.