How to Put Your Blog on the Fediverse
Tags: fediverse, beginners, programming, php
Published: 2023-08-26 22:46:09

## History/Why I should care about Mastodon or Fediverse
Recently, there has been an influx of people who want autonomy in social media. People value their privacy and wonder why we must go to X.com, Facebook.com, or Instagram.com to socialize? Why can't we start our own social media?

Only recently, the answer was that building social media is expensive and complicated. However, this is changing thanks to new W3C protocols. 

Mastodon takes most of the credit for adopting these new protocols because they built a clone of  X (formerly Twitter) that operates in the Fediverse.  

## How the Fediverse Exists
The Fediverse is a federation of servers that agree to communicate via the ActivityPub (AP) protocol. Like HTTP, SMTP, DNS, etc., the AP protocol specifies how servers should communicate to act as a social media website.

For example, email protocols require all email clients/servers to adhere to a set of rules. Those rules dictate how an email message is sent and received. This makes it possible to send a message from yahoo.com to google.com to example.com without a centralized authority. 

### Fediverse FAQ

#### So what does this mean for social media?
It means you can have a username like `wadecodez` and a custom domain name like `dev.to`, and when the handle `wadecodez@dev.to` makes a post, it will be available to all other platforms. Post once communicate everywhere.

#### Does My Platform Need to be a Twitter Clone?
No. Anything that follows the ActivityPub specification is valid. It could be your blog, your todo app, or something entirely different.

#### Then what is Mastodon? 
Mastodon is an implementation of the AP protocol that **chooses** to behave like X (formerly Twitter). Sites that implement the AP protocol are free to exist and act however they want. Sites like `https://pxlmo.com` and `https://peertube.tv/` are totally separate ideas, but they can communicate with Mastodon. **It is up to your server to respect the content of the other servers.**

#### Do I need to make a Mastodon instance to join the Fediverse? 
No. As long as you implement the bare minimum, your blog can be a member of the Fediverse!

## How to create the bare minimum to join the fediverse
Choose your language/framework of choice to receive HTTP requests. Python, Ruby, Node, PHP. Then, you'll create endpoints for discovering users, querying user profiles, and returning the contents of the inbox/outbox.

### 1. Allow for discovery
The rest of the internet needs a way to check if your server is a member of the Fediverse. This is done according to the WebFinger protocol. When the endpoint returns a valid JSON response, with a content type of `application/jrd+json`, other websites assume your server supports Fediverse activity.

```php
// handles https://example.com/.well-known/webfinger?resource=acct:alice@example.com

Route::get('/.well-known/webfinger', function (Request $request) {
    //todo should be dynamic and validated

    $subject = 'acct:alice@example.com';
    $handle =  '@example.com';
    $username = Str::between($subject, 'acct:', $handle);

    return myJson([
        'subject' => $subject,
        'aliases' => [
            'https://example.com/users/alice',
        ],
        'links' => [
            [
                "rel" => "http://webfinger.net/rel/profile-page",
                "type" => "text/html",
                "href" => 'https://example.com/users/alice',
            ],
            [
                'rel' => 'self',
                'type' => 'application/activity+json',
                'href' => 'https://example.com/activityPub/users/alice',
            ]
        ],
    ]);
});
```

### 2. Query the User's profile
The code above specifies the `https://example.com/activityPub/users/alice` supports the `application/activity+json` content type. When the rest of the internet sees this URL, they expect you to return an ActivityPub `Person` type. [See specification](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-person)

But because most websites expect this Person to be an Actor, we also need to meet the [specification](https://www.w3.org/TR/activitypub/#actor-objects) for an Actor type:

```php
Route::get('/activityPub/users/{user}', function (Request $request, User $user) {
    return myJson([
       '@context' => 'https://www.w3.org/ns/activitystreams',
       'type' => 'Person',
       'id' => 'https://example.com/activityPub/users/alice',
       'name' => 'Test User',
       'preferredUsername' => 'alice123',
       'summary' => 'my favorite food is pizza',
       'inbox' => 'https://example.com/activityPub/users/alice/inbox',
       'outbox' => 'https://example.com/activityPub/users/alice/outbox',
    ]);
})->name('activityPub.user');
```

### 3. Return an Empty inbox and Outbox
The last thing to do is to ensure the inbox/outbox contains data. Both boxes are an `OrderedCollection`. [see spec](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-orderedcollection) When you go live these endpoints will need to acknowledge incoming POST requests. This means you need to send a POST request back to the initiator of the request.

```php
Route::get('/activityPub/users/{user}/inbox', function (Request $request, User $user) {
    return myJson([
        '@context' => 'https://www.w3.org/ns/activitystreams',
        'summary' => 'Inbox for alice',
        'type' => 'OrderedCollection',
        'totalItems' => 0,
        'orderedItems' => [],
    ]);
})->name('activityPub.inbox');

Route::get('/activityPub/users/{user}/outbox', function (Request $request, User $user) {
    return myJson([
        '@context' => 'https://www.w3.org/ns/activitystreams',
        'summary' => 'Outbox for alice',
        'type' => 'OrderedCollection',
        'totalItems' => 0,
        'orderedItems' => [],
    ]);
})->name('activityPub.outbox');
```

## You are now in the Fediverse!
When you deploy your app and serve over HTTPS, you should see your profile through sites like Mastodon. **You may have to log in to said platform to trigger account discovery.**

![Proof that it works](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/774y3d08x6f5h9cl88ie.png)

## Now what? 
Implement other parts of the protocol, but do whatever you want. Make a blog, make a todo app, make something exiting and anything that follows the protocol will be visible throughout the Fediverse!