StaticPub
An attempt to make a static ActivityPub instance.
TL;DR:
ActivityPub is a protocol over HTTP that returns ActivityStreams 2.0 documents,
this /hack/ generates these JSON+LD files from static Markdown files (plus a config file).
Usage
To setup the instance, one needs to edit the instance.cfg file (it's pretty well documented). Once that's done, just run on a shell:
python staticpub.py
This will use by default instance.cfg
as the config file and generate the directories for our single user instance content.
Can I have more than one user?
Technically, yes, practically, no: At least, not using Github; you can only define just one CNAME record, pointing to a single directory. In case you have a VPS (or similar) and can setup multiple domains pointing to multiple directories in the webserver config, it could work.
Anyway, in this case, you'll need to create an extra config file (which can be done by copying over the instance.cfg
as something.cfg
) and edit its settings.
Then simply run on a shell:
python staticpub.py something.cfg
And as a result, you'll end up with a similar file structure but each user will have their "endpoints" contained in their directory (See Paths.usersEndpoint
section in the config file).
How does it works?
There are thousand of blog posts and documentation scattered all over the Internet talking about AP, but what does a single user instance needs to be up and running? Not much apparently.
Github Actions
For this to work using Github Actions, you'll need to setup a new workflow that:
- Looks in a given branch for changes on:
staticpub.py
and "entries directory"- hint: the code was updated or a new entry was added
- Run these steps:
- checkout the code
- setup Python (3.10)
- run StaticPub
- commit modified files
- push changes
You can always take a look to the actual workflow to see the real thing.
Two things to keep in mind:
- In
Settings > Pages > Build and deployment
, you'll have to chooseGithub Actions
.
- In
Settings > Actions > General > Workflow permissions
, you'll need to selectRead and write permissions
to allow pushing to the repo.
Endpoints
The Actor objects section, establishes that Actor
objects must have the following properties:
inbox
, incoming Activitiesoutbox
, outgoing Activitiesfollowing
, Actors we're followingfollowers
, Actors that follows uspreferredUsername
, our handle- plus a couple of other properties
Additionally, the Mastodon blog has documentation on Webfinger. This is a protocol that can be used to discover users on the internet. So besides inbox
, outbox
, etc, we're going to need a .well-known/webfinger
endpoint.
So, basically, what we really need are barely 6 or 7 endpoints:
{preferredUsername}
outbox
following
followers
posts/{noteId}
.well-known/webfinger
- Note that this endpoint requires a query param, but we'll ignore it.
- And optionally:
featured
How to format "Entries"
In this context, "Entries" are Markdown files with a pretty simple header that should contain at least type
and published
properties.
---
type: Note
published: 2023-01-30T21:08:00Z
---
This is an example for the StaticPub README file!
which will converted to something like:
{
"@context": "...",
"type": "Note",
"id": "https://...",
"content": "This is an example for the StaticPub README file!",
"published": "2023-01-30T21:08:00Z"
}
instance.cfg
The instance.cfg is nothing more than a simple INI File. It's well documented so anything you might want to know, it's already there.
staticpub.py
It receives an optional parameter that references an instance.cfg
, and will take its configurations from the instance.cfg
file to build everything. In case you want to have a multi user instance you need to have multiple config files, that's all.
Things missing
Inbox
This endpoint requires a bit of trickery but since it's a static instance, we can't implement:
That is, when an instance receives a POST
to this endpoint, it needs to verify the remote user Public Key to verify it's authenticity (using HTTP Signatures
), but again, since it's static we can't process POST
and much less verify OpenSSL keys.
Following
The case is similar to /inbox
. We can't simply process federated requests.
Delivery
Since we can't have followers (i mean, it's a hardcoded empty endpoint), we can't send anything to anyone. But, let's say, we do have them: We would need to setup a (GH Action) Workflow that walks through the followers and POST
s to their instances our activities. Also, we'd need to provide our Public Key, for verification.
So, in theory, this could be done, probably.
Can I use other CI than Github Actions?
Yes, totally. This can run on anything that can run Python 3.10+
(mostly because Union
type hints are written as X | Y
instead of Union[X, Y]
).
References
There's a great blog post by Justin Garrison:
- https://www.justingarrison.com/blog/2022-12-06-mastodon-files-instance/
- https://github.com/rothgar/static-mastodon
Also, there's a somewhat detailed blog post in the Mastodon blog:
The W3C ActivityPub Recommendation has a very detailed document with all the info you might need for a more robust implementation.
LICENSE
See LICENSE