ActivityPub on a (mostly) static site

Mon, 08 May 2023 10:00:00 +0000
activitypub, mastodon

Following on from this post, for anyone who's interested in getting ActivityPub integrated on their static site, this is what I've needed to setup/build (some of this may indeed be redundant, but it 'evolved' over time, so easier just to leave alone than fix).

Some not-hugely-relevant background: I have a custom-built site generator, written in Python, pushing files via git to a Gitea instance and pulled via a cronjob to a dir where they're served by Apache2 (with Cloudflare in front). Everything is static, apart from (now) the inbox required for ActivityPub to work.

In terms of static ActivityPub content, there are a bunch of JSON files required (I'll probably butcher the descriptions of these, but whatever ¯\_(ツ)_/¯ ):

actor - effectively your ActivityPub profile information, but importantly this also has your public key.

followers - this is an OrderedCollection (an ActivityStreams term) of your followers. For some reason (I forget why now) I'm just pointing this to a separate JSON file: followers-list with the actual followers.

outbox - this is the actual content you post in another OrderedCollection.

Along with these, I've got another JSON "profile"...

jasonrbriggs@jasonrbriggs.com.json

...which is used for webfinger (more on that shortly).

My rewrite rules for the first set of files look like this:

RewriteRule ^actor$ /@me/actor [R=301,L]
RewriteRule ^@me$ /@me/actor [R=301,L]
RewriteRule ^@me/$ /@me/actor [R=301,L]
RewriteRule ^@jasonrbriggs$ /@me/actor [R=301,L]
RewriteRule ^@jasonrbriggs/$ /@me/actor [R=301,L]
RewriteRule ^followers$ /@me/followers

# force content type
RewriteRule @me/actor - [env=headerjs:1]
Header set Content-type application/activity+json env=headerjs
RewriteRule @me/outbox - [env=headerjs:1]
Header set Content-type application/activity+json env=headerjs

For the aforementioned webfinger, there's one more rewrite rule:

RewriteCond %{QUERY_STRING} (?:^|&)(resource=acct:jasonrbriggs@jasonrbriggs.com$) [NC]
RewriteRule ^\.well-known/webfinger /profile/jasonrbriggs@jasonrbriggs.com.json [L]

That takes care of the discovery aspects of the process (the self link in the webfinger profile points to the actor).

I do have a couple more rewrite rules for the @me directory which redirect browser requests (basically for text/html) to my local archive of "micro posts":

RewriteCond %{HTTP:Accept} text/html [NC]
RewriteRule ^@me$ /micro/ [R=301,L]
RewriteCond %{HTTP:Accept} text/html [NC]
RewriteRule ^@me/$ /micro/ [R=301,L]

(Why "@me"? Because I was originally planning @me@jasonrbriggs.com as my ActivityPub address, before changing my mind and going with @jasonrbriggs@jasonrbriggs.com, and I never got around to fixing).

As mentioned, the only part of my site which is (unfortunately) not static is the ActivityPub inbox, because you need to be able to accept POST follow requests and other notification activities from the fediverse. For the inbox, I've built a very simple Flask/WSGI app to do the very minimum (just file-based, no database, hopefully as minimal impact as possible).

I've also built a local (ie. not web-based) command-line Python app which can be used to send an Accept activity to a follow request (it should also add the follower to the follower's list, but I haven't gotten around to that yet); additionally, it retrieves all new posted content from the outbox and delivers that content to each follower's inbox. I'm not posting the code to github - at least not yet - because...