2022-06-12 19:20:02 -04:00
|
|
|
---
|
2023-02-09 20:19:30 -05:00
|
|
|
date: 2022-06-12 18:35:30-04:00
|
2022-06-12 19:20:02 -04:00
|
|
|
draft: false
|
|
|
|
math: false
|
2023-01-05 14:04:45 -05:00
|
|
|
medium_enabled: true
|
2023-02-09 20:19:30 -05:00
|
|
|
medium_post_id: 3c4fe896f3fb
|
|
|
|
tags:
|
|
|
|
- Mastodon
|
|
|
|
title: Having your Website Visible on the Fediverse
|
2022-06-12 19:20:02 -04:00
|
|
|
---
|
|
|
|
|
|
|
|
[ActivityPub](https://www.w3.org/TR/activitypub/) is the backbone
|
|
|
|
of the [Fediverse](https://en.wikipedia.org/wiki/Fediverse).
|
|
|
|
Implementing this protocol will allow one to interact with users on
|
|
|
|
[Mastodon](https://joinmastodon.org/),
|
|
|
|
[Pixelfed](https://pixelfed.org/),
|
|
|
|
[Friendica](https://friendi.ca/),
|
|
|
|
and [others](http://fediverse.party/).
|
2022-12-17 23:48:56 -05:00
|
|
|
Unfortunately for a static website, this protocol uses a
|
2022-06-12 19:20:02 -04:00
|
|
|
publish-subscribe pattern. A service would need to be written
|
|
|
|
in order to handle subscribers, pushing messages of published items,
|
|
|
|
as well as receiving mentions.
|
|
|
|
At the current state of my website, I am uninterested in creating
|
|
|
|
such a service. However, I do wish to document the parts
|
|
|
|
of the ActivityPub protocol I was able to implement so far
|
|
|
|
using only a static website.
|
|
|
|
This post extends off of
|
|
|
|
[Eugen Rochko's work](https://blog.joinmastodon.org/2018/06/how-to-implement-a-basic-activitypub-server/)
|
|
|
|
which I encourage you to check out.
|
|
|
|
|
|
|
|
## Webfinger
|
|
|
|
|
|
|
|
When someone looks up a handle on Mastodon, it performs a Webfinger
|
|
|
|
lookup. For example if I am looking up the user `brozek@brandonrozek.com`,
|
|
|
|
then the service will perform a GET request at
|
|
|
|
`https://brandonrozek.com/.well-known/webfinger?resource=acct:brozek@brandonrozek.com`.
|
|
|
|
|
2022-12-17 23:48:56 -05:00
|
|
|
A Webfinger request should return the handle of the user (the `subject`) as well as
|
2022-06-12 19:20:02 -04:00
|
|
|
a link to its `actor`.
|
|
|
|
|
|
|
|
```json
|
|
|
|
{
|
|
|
|
"subject": "acct:brozek@brandonrozek.com",
|
|
|
|
|
|
|
|
"links": [
|
|
|
|
{
|
|
|
|
"rel": "self",
|
|
|
|
"type": "application/activity+json",
|
|
|
|
"href": "https://brandonrozek.com/brozek.json"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2022-12-17 23:48:56 -05:00
|
|
|
Now for a static site with one user, you can hardcode the Webfinger directly
|
2022-06-12 19:20:02 -04:00
|
|
|
at `.well-known/webfinger`. The only issue is that many webservers determine the
|
2022-12-17 23:48:56 -05:00
|
|
|
mime-type of a file by its extension. In this case, we'll have to let the webserver
|
2022-06-12 19:20:02 -04:00
|
|
|
(mine is nginx) know how to serve it.
|
|
|
|
|
|
|
|
```nginx
|
|
|
|
location /.well-known/webfinger {
|
|
|
|
default_type application/jrd+json;
|
|
|
|
add_header Access-Control-Allow-Origin "*";
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
## Actor
|
|
|
|
|
|
|
|
An actor defines how to interact with a user as well as its metadata.
|
|
|
|
This file also needs to be served with the `application/jrd+json` header.
|
|
|
|
Below is an example of what I have on my website as well as how it looks
|
|
|
|
on Mastodon.
|
|
|
|
|
|
|
|
```json
|
|
|
|
{
|
|
|
|
"@context": [
|
|
|
|
"https://www.w3.org/ns/activitystreams",
|
|
|
|
"https://w3id.org/security/v1"
|
|
|
|
],
|
|
|
|
"id": "https://brandonrozek.com/brozek.json",
|
|
|
|
"type": "Person",
|
|
|
|
"inbox": "https://brandonrozek.com/inbox",
|
|
|
|
"outbox": "https://granary.io/url?input=rss&output=as2&url=http%3A%2F%2Fbrandonrozek.com%2Fblog%2Findex.xml",
|
|
|
|
"preferredUsername": "brozek",
|
|
|
|
"name": "Brandon Rozek",
|
|
|
|
"summary": "<p>Writings from <a href='https://brandonrozek.com'>https://brandonrozek.com</p></a><p>Social profile <a href='https://fosstodon.org/@brozek'>@brozek@fosstodon.org</a></p>",
|
|
|
|
"url": "https://brandonrozek.com",
|
|
|
|
"manuallyApprovesFollowers": false,
|
|
|
|
"discoverable": true,
|
|
|
|
"published": "2022-05-17T00:00:00Z",
|
|
|
|
"icon": {
|
|
|
|
"type": "Image",
|
|
|
|
"mediaType": "image/jpeg",
|
|
|
|
"url": "https://brandonrozek.com/img/avatar.jpg"
|
|
|
|
},
|
|
|
|
"publicKey": {
|
|
|
|
"id": "https://brandonrozek.com/brozek.json#main-key",
|
|
|
|
"owner": "https://brandonrozek.com.com/brozek.json",
|
|
|
|
"publicKeyPem": "-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
![Screenshot of brozek@brandonrozek.com profile on Mastodon](/files/images/blog/202206121902.png)
|
|
|
|
|
|
|
|
## Limitations and Conclusion
|
|
|
|
|
|
|
|
Notice in the previous screenshot that it says "Cancel Follow Request".
|
|
|
|
This is because my static website is not equipped to handle a follow request.
|
|
|
|
Standard ActivityPub servers keep an inventory of all the users that follow
|
|
|
|
their users and who each user on the server is following.
|
|
|
|
|
|
|
|
The outbox defines items that the user has published.
|
|
|
|
I have it pointed to an activity JSON feed generated directly
|
|
|
|
from my RSS using granary.io.
|
|
|
|
Mastodon correctly displays the number of blog posts I have,
|
|
|
|
but sadly it does not show any of them. I'm not entirely
|
|
|
|
sure why, though my hypothesis is that the posts need to be pushed
|
|
|
|
to the Mastodon server when its created. It could also be that the
|
|
|
|
actor isn't defined properly in the activity JSON feed. If you happen
|
2023-02-09 20:19:30 -05:00
|
|
|
to know please get in touch.
|