Implementing ActivityPub on Netlify using serverless functions

I’m excited to get involved with ActivityPub, and I decided it would be cool to set my blog up as a node in the fediverse. I’ve read a few documents describing activities, the inbox, and the outbox so I figured I would start with a minimal implementation. My blog runs on Netlify, which supports serverless functions that I will use to implement my inbox and outbox.

I followed this article about getting set up, and webfinger and actor are working.

I set up a user on a Mastodon instance at https://fosstodon.org, then I searched for my user hosted by my blog and it worked. The search is @william@william.cool

That’s good, but then when I actually open my blog user’s profile on fosstodon, I see no toots. Even though it correctly shows the total as 16, and I know it’s hitting my outbox endpoint because I can look at the logs for my blog.

Ok, so then I try to follow my blog user and my inbox endpoint never gets called, so I can’t complete the follow request.

I’m starting to feel like Mastodon expects additional API endpoints other than just the ActivityPub spec, but I’m still confused why my inbox is not getting called when I try to follow my self hosted account.

Am I trying to do something ActivityPub was not intended for? I’d be happy to give any additional info, any suggestions are greatly appreciated.

1 Like

Weirdly, the webfinger resolution works, but i get a timeout when trying to search for your actor ID, which seems to indicate that there’s something wrong with the way your Actor is being served. I’m seeing a Content-Type: text/plain response—you should make sure that it gets served with the proper application/activity+json content type, or it might break some servers.

Mastodon doesn’t read posts from the outbox. You have to POST activities to your follower’s inbox before Mastodon will display or process them.

I’d need more info to debug this—I sent both a DM and a follow request from my local server (cybre.space) and they seemed to go through successfully. Do you have anything in your logs?

Ok, cool. I fixed the Content-Type for the Actor to be application/activity+json, thanks for that!

I’m not seeing DM’s or follow requests from your server in the logs, but I was able to confirm that the endpoint works by using this curl command
curl -X POST -H "Content-Type: application/activity+json" -d @follow-activity.json https://william.cool/.netlify/functions/inbox

This is the contents of follow-activity.json

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "id": "https://fosstodon.org/users/wlindner/follow/240782",
  "type": "Follow",
  "actor": "https://fosstodon.org/users/wlindner",
  "object": "https://william.cool/actor"
}

It all comes through, so I’m not sure why your requests did not. Even stranger, I am seeing POST requests with Activity Json from various Mastodon servers with the Activity Type of Delete. If I had to guess, I’d say they are accounts that are getting deleted, and Mastodon must propagate that through all of the inboxes it knows about, or something? So… I guess it is able to find my inbox, it’s just not sending the DMs or Follow requests for some reason.

What are you trying to do when you say “search for your actor ID”? Maybe I set up webfinger wrong. It doesn’t do a lookup, it’s just a static file that serves json since I only have 1 user.

Both
https://william.cool/.well-known/webfinger
and
https://william.cool/.well-known/webfinger?resource=acct:william@william.cool
return what I expect and don’t time out for me.

Hi William,

I’ve been running through similar issues you mentioned in your first message.

I see my profile correctly in mastodon. It query the WebFinger URL and read the actor file correctly. But no way to make the messages work on static files served via HTTP GET requests.

After having fetch the WebFinger and actor file, Mastodon seems to query the inbox URL via a POST request (this request fails because of no server side logic) and never tries to fetch the existing public messages from the outbox URL via a simple GET request.
The issue is that it is impossible to handle POST requests without some server logic.
Static implementations can only work via HTTP GET…

May be you have made some progress since 2020?

yes, the /inbox should handle POST requests, hence the serverless functions mentioned in the title

I have a (work-in-progress) implementation here: GitHub - musakui/kotori-netlify: minimal ActivityPub instance on Netlify