A (tiny, incomplete, single user, write-only) ActivityPub server in PHP
I've written an ActivityPub server which only allows you to post messages to your followers. That's all it does. It won't record favourites or reposts. There's no support for following other accounts or receiving replies. It cannot delete or update posts nor can it verify signatures. It doesn't have a database or any storage beyond flat files.
But it will happily send messages and allow itself to be followed.
This shows that it is totally possible to broadcast fully-featured ActivityPub messages to the Fediverse with minimal coding skills and modest resources.
Why
I wanted to create a service a bit like FourSquare. For this, I needed an ActivityPub server which allows posting geotagged locations to the Fediverse.
I didn't want to install a fully-featured server with lots of complex parts. So I (foolishly) decided to write my own. I had a lot of trouble with HTTP Signatures. Because they are cursed and I cannot read documentation. But mostly the cursed thing.
How
Creating a minimum viable Mastodon instance can be done with half a dozen static files. That gets you an account that people can see. They can't follow it or receive any posts though.
I wanted to use PHP to build an interactive server. PHP is supported everywhere and is simple to deploy. Luckily, Robb Knight has written an excellent tutorial, so I ripped off his code and rewrote it for Symfony.
The structure is relatively straightforward.
/.well-known/webfinger
is a static file which gives information about where to find details of the account./[username]
is a static file which has the user's metadata, public key, and links to avatar images./following
and/followers
are also static files which say how many users are being followed / are following./posts/[GUID]
a directory with JSON files saved to disk - each ones contains the published ActivityPub note./photos/
is a directory with any uploaded media in it./outbox
is a list of all the posts which have been published./inbox
is an external API endpoint. An ActivityPub server sends it a follow request, the endpoint then POSTs a cryptographically signed Accept message to the follower's inbox. The follower's inbox address is saved to disk./logs
is a listing of all the messages received by the inbox./new
is a password protected page which lets you write a message. This is then sent to.../send
is an internal API endpoint. It constructs an ActivityPub note, with attached location metadata, and POSTs it to each follower's inbox with a cryptographic signature.
That's it.
The front-end grabs my phone's geolocation and shows the 25 nearest places within 100 metres. One click and the page posts to the /send
endpoint which then publishes a message saying I'm checked in. It is also possible to attach to the post a short message and a single photo with alt text.
There's no database. Posts are saved as JSON documents. Images are uploaded to a directory. It is single-user, so there is no account management.
What Works
- Users can find the account.
- Users can follow the account and receive updates.
- Posts contain geotag metadata.
- Posts contain a description of the place.
- Posts contain an OSM link to the place.
- Posts contain a custom message.
- Posts autolink #Hashtags (sort of).
- Posts can have an image attached to them.
- Messages to the inbox are recorded (but not yet integrated).
ToDo
- My account only has a few dozen followers, some of whom share the same sever. Even with cURL multi handle, it takes time to post to several servers.
- It posts plain text. It doesn't autolink websites
- Hashtags are linked when viewed remotely, but they don't go anywhere locally.
- There's no language selection - it is hard-coded to English.
- The outbox isn't paginated.
- The UI looks crap - but it is only me using it.
- There's only a basic front-page showing a map of all my check-ins.
- Replies are logged, but there's no easy way to see them.
- Doesn't show any metadata about the place being checked-in to. It could use the item's website (if any) or hashtags for the type of amenity it is.
- No way to handle being unfollowed.
- No way to remove servers which have died.
- Probably lots more.
Other Resources
I found these resources helpful while creating this project:
- MVP ActivityPub in Python on Glitch
- Understanding ActivityPub Part 1: Protocol Fundamentals
- Activity Notes
- Federating with GoToSocial
What's Next?
I've raised an issue on Mastodon to see if they can support showing locations in posts. Hopefully, one day, they'll allow adding locations and then I can shut this down.
The code needs tidying up - it is very much a scratch-my-own-itch development. Probably riddled with bugs and security holes.
World domination?
Where
You can laugh at my code on GitHub.
You can look at my check-ins on a map.
You can follow my location on the Fediverse at @edent_location@location.edent.tel
That's a fair point. But I think I disagree. I don't want a separate account for FourSquare, Untappd, BookWyrm, etc. I'd rather have one account with many channels. But, as you say, it is good to have a diversity of extensible tools.
<a href="https://www.openstreetmap.org/?mlat=" rel="nofollow noopener noreferrer"><span>https://www.</span><span>openstreetmap.org/?mlat=</span><span></span></a>${latitude}&mlon=${longitude}<a href="https://mastodon.social/tags/map" rel="tag">#<span>map</span></a>=19/${latitude}/${longitude}
) map OpenStreetMapMore comments on Mastodon.