# Yonder — An uncompromising ActivityPub server



[[TOC]]

## Reasons for yet another ActivityPub server

### The beginning — Mastodon

I've been running Mastodon-compatible services for a while, starting with my first now defunct Mastodon instance at `social.platypush.tech`.

[Mastodon](https://joinmastodon.org) is a great gateway drug for the Fediverse, but it soon started to feel tight for me.

Features often land in Mastodon only when other federated platforms have already embraced them for a while (e.g. [post edits](https://github.com/mastodon/mastodon/pull/19103)), and they often land in ways that are incompatible with what other platforms have already implemented (e.g. [quotes](https://fediverse.codeberg.page/fep/fep/044f/)).

And many other features that I wanted for a rich social media experience ([emoji reactions](https://github.com/mastodon/mastodon/issues/4106), [Markdown support](https://github.com/mastodon/mastodon/issues/23981), [configurable number of profile fields](https://github.com/mastodon/mastodon/issues/29906), [configurable maximum number of characters](https://fouquet.me/2023/09/22/mastodon-char-limit), [configurable number of media attachments](https://github.com/mastodon/mastodon/issues/24461), [Webmentions](https://github.com/mastodon/mastodon/issues/1384), [backfilling of statuses and other activities from remote instances](https://github.com/mastodon/mastodon/issues/34), [code blocks](https://github.com/mastodon/mastodon/issues/13544), inline images, custom frontends, [LaTeX formulas](https://github.com/mastodon/mastodon/issues/822), [a simpler and more complete process for account migrations](https://github.com/mastodon/mastodon/issues/12423)...) just never landed at all.

I ended up, like many others, maintaining [my own fork of Mastodon](https://github.com/blacklight/mastodon/tree/v4.2.0-mods), with all the patches for features I wanted and that would have probably never been merged upstream.

At some point I realized that keeping my own fork up-to-date with all the upstream changes wasn't worth the effort, and I started to look for a better way to run Mastodon-compatible services.

Another factor that influenced my decision was Mastodon's unjustifiably high resource footprint.

My old instance used to run on a dedicated VPS with 8 GB of RAM and 500 GB of disk space.

It only had me and another active user on it.

And yet all the federated load, with all of its eager operations managed by a bloated Ruby-on-Rails + Sidekiq stack, was sufficient to choke everything, even if I regularly ran cleanups.

### Down the rabbit whole — Akkoma

At some point I started looking around for federated alternatives compatible with Mastodon that had a much lower resource footprint and provided most of the features I wanted.

I soon discovered [Akkoma](https://akkoma.dev/AkkomaGang/akkoma/), and I've used it for a few years as my main driver - the last instance was `manganiello.eu`.

Akkoma filled many of Mastodon's gaps that mattered to me:

- Markdown posts
- Configurable number of post characters
- Configurable number of profile fields
- Code blocks (no syntax highlighting though)
- Emoji reactions
- Custom frontends (but not customizable on a user level)

It still left some gaps, especially some compatibility gaps with Mastodon ([`indexable` flag on accounts](https://akkoma.dev/AkkomaGang/akkoma/pulls/1051), [support for Mastodon quotes](https://akkoma.dev/AkkomaGang/akkoma/pulls/1086), [remote profile badge verification](https://akkoma.dev/AkkomaGang/akkoma/pulls/1152)...), but for a long while I was satisfied with what it provided.

Until recently I was also the maintainer of the [AUR `akkoma` package](https://aur.archlinux.org/packages/akkoma) (now looking for a new maintainer).

But after a while I also started to feel uncomfortable with Akkoma's limitations.

Mastodon-compatible quotes were a dealbreaker, and my implementation failed to get approved upstream - ending up on the fork I ran on my instance.

Other features, like full bidirectional verification for profile badges and support for the `indexable` flag, also ended up living only on [my fork](https://git.fabiomanganiello.com/akkoma).

Other issues, like proper compatibility with `Audio` activities from e.g. [Funkwhale](https://funkwhale.it) or [Songhive](https://songhive.org), also made the experience less pleasant.

Akkoma however proved to show much more clemency towards my hardware resources than Mastodon did.

But the price to pay was to implement the features I wanted in a language (Elixir) that was quite exotic and unfamiliar to me (even though I ended up learning a lot from it).

I also couldn't find much documentation about e.g. Akkoma jobs or configuration.

I found [Akkoma's documentation](https://docs.akkoma.dev/stable/) to be quite minimal in terms of content.

Understanding some configuration options or what job to run for a particular task often required me to look at the code itself.

Another issue with Akkoma was with the frontend.

I know that the default [`pleroma-fe`](https://git.pleroma.social/pleroma/pleroma-fe) can be quite polarizing, and that people either love it or hate it.

I belonged to the category of those who, no matter what, never managed to like it.

Luckily Akkoma could be configured to use alternative frontends, and I ended up liking the style of [Soapbox](https://gitlab.com/soapbox-pub/soapbox-fe), and even more that of its fork [Mangane](https://github.com/BDX-town/Mangane).

But I still felt that those frontends weren't particularly rich in terms of features, nor particularly curated around the edges.

Plus, the admin panel was an afterthough provided as a separate frontend rather than a first-class citizen like in Mastodon, and the UX was also poorly curated.

Still, the Soapbox/Mangane style ended up heavily inspiring the design of the default Yonder frontend.

### Building Yonder

I started building [**Yonder**](https://yonder.social) ([source code](https://git.fabiomanganiello.com/yonder), [Github mirror](https://github.com/blacklight/yonder)) a while ago, as a minimal PoC for an [ActivityPub](https://activitypub.rocks/) server in [Rust](https://rust-lang.org/) .

It's been on a back burner on my hard drive for a while, but now I feel that it's mature enough to be my main driver on the Fediverse.

Yonder is a self-hosted, Mastodon-compatible [ActivityPub](https://activitypub.rocks/) server. The entire service — HTTP API, federation, streaming, media, moderation, admin panel, background jobs — is **one binary**. The only services it needs are **PostgreSQL** and **Redis**.

It speaks the [Mastodon client API](https://docs.joinmastodon.org/api/) (v1 and v2), so [Tusky](https://tusky.app/), [Ivory](https://tapbots.com/ivory/), [Elk](https://elk.zone), [Phanpy](https://phanpy.social/), [Mona](https://apps.apple.com/us/app/mona-27-for-mastodon/id6755672518) and every other Mastodon app just works when pointed at your instance.

It also implements a good subset of the Pleroma/Akkoma API dialects, which means that clients like [Moshidon](https://github.com/LucasGGamerM/moshidon) and other Pleroma-compatible apps can also access those features (e.g. Markdown content type for posts and custom emojis).

It speaks ActivityPub, so your users federate with Mastodon, Akkoma, Pleroma, Misskey and the rest of the Fediverse.

![The Yonder home timeline](https://s3.fabiomanganiello.com/fabio/img/yonder/yonder-home-dark.png)

## Name and meaning

[Yonder](https://www.vocabulary.com/dictionary/yonder) (adv. or adj., /ˈjaʊndə/) is an Old English term for "over there". Something distant but usually within sight.

I chose it as the name for this project because it relays, together with the logo (a large circle connected to three other circles), the idea of connecting things distant but within reach.

## What you get

### Posting & timelines

- Rich posts in plain text or **Markdown**, with _content warnings_, _polls_, _media attachments_ with editable alt text, _scheduled posts_, _editing_ and _saved drafts_.
- **Quote posts** with author authorization ([FEP-044f](https://codeberg.org/fediverse/fep/src/branch/main/fep/044f/fep-044f.md)-style, with fallback to [FEP-e232](https://codeberg.org/fediverse/fep/src/branch/main/fep/e232/fep-e232.md) Pleroma/Akkoma/Misskey compatible quotes), custom emoji reactions, replies, boosts and likes.
- Every **timeline** Mastodon has: home, local, federated, hashtag timelines, user-defined lists — with real-time updates over the standard Mastodon streaming WebSocket.
- **Hashtags** you can follow into your home feed and server-side filters (`warn`/`hide`/`blur`) that apply across every timeline.

![A quote post rendered in a thread](https://s3.fabiomanganiello.com/fabio/img/yonder/yonder-status-quote-dark.png)

### Social & federated

- Full ActivityPub federation via [**Pubby**](https://github.com/blacklight/pubby), with durable at-least-once delivery. I built Pubby as a general-purpose ActivityPub library that takes care of the all the plumbing behind the scenes, initially with Python bindings to power [Madblog](https://madblog.dev) and [Songhive](https://songhive.org), and it gained Rust bindings with features parity with the Python SDK in order to power Yonder - available as [`pubby-sdk`](https://crates.io/crates/pubby-sdk) crate.
- **Notifications** in-app over WebSocket, Web Push (VAPID) and email, with per-type preferences.
- A progressive Web app (**PWA**) optimized for mobile and with support for native notifications.
- The bundled Web UI ships in **five languages including full RTL support**, with light and dark themes and **custom accent colors**.
- **Custom emojis** — per-instance emoji and emoji packs.
- **Custom number of characters**, **custom number of profile fields**, **custom number of media attachments** and **custom number of pinned posts**.
- **RSS** and **Atom** feeds for profiles, tags and lists; oEmbed/embeddable status cards.

### Moderation & administration

- User-side: **mutes**, **blocks**, **reports** (optionally forwarded to the remote instance via `Flag`), server-side content **filters**.
- Instance-side: user **limiting** and **suspension**, **domain blocks**, federation **relays**, and a comprehensive **admin panel** delivered as a first-class citizen.
- Every **registration policy**: `open`, `invite-only`, `approval-required` or `closed`.

### Platform

- One **single Rust binary** — stack: `axum`, `sqlx`, `tokio`.
- OAuth2 provider with authorization-code + PKCE, device flow, and scoped revocable API tokens.
- **Pluggable frontends**: the bundled Vue 3 SPA is just the default; alternative frontends can be installed alongside it. Users **can pick their favourite frontend**, preferences are stored in the browser session.
- OpenAPI 3 spec at `/openapi.json` with **bundled Swagger UI**.
- **Safety** defaults: argon2id passwords, SSRF-guarded remote fetches, Redis-backed rate limits, TOTP two-factor.

## What's new

### Account migration

**Account migration is a first-class feature**: moving an account *to* or *from* another server, followers and all, is a supported flow, compatible with Mastodon and Akkoma.

On top of that, Yonder supports importing activities from the old account in two ways:

- Standard **CSV import/export** (compatible with Mastodon/Pleroma/Akkoma)
- OAuth2-authenticated **API fetches**.

![The accountimport/export tab in Yonder, showing custom import options over API crawlers](https://s3.fabiomanganiello.com/fabio/img/yonder/yonder-account-import.png)

You login to your old account through Yonder's interface, you pick what you want to import from your old account (including private messages, likes, boosts, replies, etc.), click "_Start remote import_", and everything from your old account will be copied over - as a native activity that originated from the new account, with the original timestamps respected.

The user can also decide whether the imported activities will fan out to federated instances or only be stored on the local database - prevents avoidable federation noise over imports, the activities can be selectively federated by simply boosting them or editing an old post.

The only thing that Yonder doesn't support is importing _received_ likes, boosts and replies - for the simple reason that it doesn't want to forge federated activities or rewire threads in ways that don't reflect what other instances see.

The UX of the account migration flow has also been re-thought as a step-by-step process (connecting the old account over OAuth2, importing the data over API crawlers or CSV backups, reviewing the import process, creating an alias and moving followers), making the process much more intuitive and mistakes harder.

![Account migration page](https://s3.fabiomanganiello.com/fabio/img/yonder/yonder-account-migration-dark.png)

### See the full federated picture all the time

One of the most confusing (and often infuriating) things about the Fediverse is that what you see on your local instance is often a very small subset of what's actually available on the Fediverse (unless you are on a large instance like `mastodon.social`, and even in that case many activities from the fringes of the Fediverse are lost).

Your instance only receives what its peers send to it. And an instance's peers depend on who your users follow, which relays you wired your instance to, and who your users interact with.

This has an unintended consequence: that **content that never reaches your instance is invisible to you**. Unless you trigger an explicit fetch, e.g. through a search query or some import job. And even then, you probably won't see a lot of likes, boosts and replies a remote activity has received, nor the real number of followers of a user.

Yonder solves this problem by adding a couple of new endpoints to the standard Mastodon API, and slightly modifying how some of the existing endpoints behave in order to maintain back-compatibility with existing apps.

- [`/api/v1/accounts/{id}/sync_remote`](https://manganiello.tech/swagger-ui/#/accounts/sync_remote). This allows users to explicitly sync the latest `<n>` activities from the account `{id}` from the remote instance to the local database.
  If your Mastodon instance sees an account for the first time, and no local users follow that account, their timeline will probably appear empty, and they will show as having zero followers/followed accounts.
  Yonder fixes this visibility gap by adding a "_Sync with `<remote-instance>`_" button next to remote profiles, which triggers a remote fetch for their next `<n>` activities.
- **Followers** and **followed** accounts are also synchronized with the remote instance, so you see the actual numbers. Upon calls to the `/followers` endpoint, the list is lazily fetched and you can navigate it from your local instance - without having to open the original profile URL to see the actual numbers.
- [`/api/v1/statuses/{id}/fetch_remote_context`](https://manganiello.tech/swagger-ui/#/statuses/fetch_remote_context). This endpoint is called by the Yonder frontend whenever you expand a post that belongs to a remote thread.
  What it does is to fetch behind the scenes all the statuses that belong to **the same parent line**, with a default maximum depth of 20.
  This, in my opinion, matches the expected behavior from a social app user. If I see a comment from a friend on another thread and I click on it, the most relevant thing I want to see is the direct path of statuses from the root of the thread down to the status I clicked on, plus the next 2-3 direct children.
  The client ends up seeing exactly the same context as the instance of the post's author. This is back-compatible also with existing Mastodon apps - calls to the `/context` endpoint will trigger `/fetch_remote_context` behind the scenes if needed, and a refresh of the status 2-3 seconds later should show all the expanded remote posts in that path.
  Siblings and descendants from other paths are not fetched by default, but they are fetched if the user expands statuses on those paths.
  This approach means that fetches of remote threads provide a much more **complete picture** than that provided by Mastodon by default (you get to see exactly the same view as the author of that post, not only the subset explicitly send to your instance), while simultaneously being **more efficient** than what e.g. Mastodon does (fetch overhead is capped by the depth of the path, set to 20 by default, instead of trying to eagerly fetch the whole tree with no boundaries).

### Another handful of useful API extensions

- [`POST/DELETE /api/v1/accounts/{id}/subscribe`](https://manganiello.tech/swagger-ui/#/accounts/subscribe_account): subscribe/unsubscribe to an account's activities without publicly following them.
- [`GET /api/v1/trends/tags`](https://manganiello.tech/swagger-ui/#/trends/tags_trending): browse global or local trending hashtags, with support for pagination and time ranges.
- [`POST /api/v1/admin/accounts/{id}/reset_password`](https://manganiello.tech/swagger-ui/#/admin/reset_password): programmatically send a user password reset link directly to their email.
- [`POST /api/v1/admin/statuses/{id}/action`](https://manganiello.tech/swagger-ui/#/admin/status_action): apply granular moderation to individual statuses (delete, mark as sensitive, add content warning).

### Trending hashtags

This is something that for some reason Mastodon removed at some point, but that I find very useful.

![Screenshot of Yonder's hashtag page, showing filters and temporal selection](https://s3.fabiomanganiello.com/fabio/img/yonder/yonder-hashtags-page-dark.png)

Yonder makes it easy not only to follow hashtags, but to have a view of all the hashtags that are trending over the local instance or over all the known Fediverse, over a given period of time, and with support for pagination.

### Direct messages as real conversations

Direct messages in Yonder are real conversations, not just an ungrouped timeline of cards with a lock on them.

![Screenshot of Yonder's direct messages page, grouped by conversation](https://s3.fabiomanganiello.com/fabio/img/yonder/yonder-messages-dark.png)

This is similar to what users expects by social networks like X, Facebook or Instagram - private messages are not a timeline, they are grouped conversations, and it should be easy to find a private message from a month ago even if you received hundreds of messages on a single unrelated conversation in the meantime.

### Webmentions

[Webmentions](https://indieweb.org/Webmention) are first-class citizens supported in both directions.

What this means is that:

- If a blog or federated actor `example.blog` that supports Webmentions posts a link to `example.social/status/123`, `example.social` will process the Webmention and render it as a normal reply or reaction. The Webmentions actor will also be transparently rendered as a virtual user on the platform.
- If you link `example.blog` in a post on `example.social`, and `example.blog` supports Webmentions, then the target will receive a Webmention request, and your social activity may be natively rendered under the blog article.

Webmentions are powered by my [`webmentions`](https://git.fabiomanganiello.com/webmentions) library - which, just like Pubby, was initially built in Python to support Webmentions on Madblog and Songhive, and then ported to Rust with features parity with the Python SDK - available as [`webmentions-sdk`](https://crates.io/crates/webmentions-sdk) crate.

### LaTeX

Instances like `mathstodon.xyz` run their own forks of Mastodon with support for LaTeX formulas.

But they use [MathJax](https://www.mathjax.org), which means that formulas are only rendered on the frontend, and only if you see them from that instance.

Yonder goes one step further and it adds rendering of LaTeX formulas directly on the backend.

You can provide your rendering script, set `math.enabled = true` in your configuration, and set `math.command` to your LaTeX rendering command.

Any command that takes the LaTeX formula on the stdin and returns an image on stdout works.

The repository ships a [`latex-math-render.sh` script](https://git.platypush.tech/blacklight/yonder/src/branch/main/scripts/latex-math-render.sh) that is already compatible with `tectonic` and `pdflatex`.

![A Yonder post with inline LaTeX formulas](https://s3.fabiomanganiello.com/fabio/img/yonder/yonder-latex.png)

Being rendered on the backend, the formulas are also rendered on clients that don't support frontend rendering through MathJax.

If the server or the client support inline images (e.g. Phanpy), then formulas will be rendered inline.

If it supports math-type attachments, then the formulas will be rendered at the bottom of the post.

Otherwise, they will graciously fall back to image attachments, with LaTeX-style references (`(1)`, `(2)`...) as links in the post.

![A Yonder post with inline LaTeX formulas shown in the Mastodon UI, with LaTeX formula falling back to media attachments, and inline links to the images](https://s3.fabiomanganiello.com/fabio/img/yonder/mastodon-latex.png)

### Inline images

Yonder supports inline images via standard Markdown:

```markdown
![This is an inline image](https://example.com/image.png)
```

![Screenshot of Yonder's hashtag page, showing filters and temporal selection](https://s3.fabiomanganiello.com/fabio/img/yonder/yonder-inline-images.png)

### Embeddables

Embed your posts in blog, Websites and anywhere on the Web. Click on the context menu of a post, select "_Embed_", and copy the snippet:

```html
<div class="yonder-embed" data-status="{status-id}">
  <a href="https://{instance}/statuses/{status-id}/embed">Post by @{user}@{instance}</a>
</div>
<script async src="https://{instance}/embed.js" charset="utf-8"></script>
<noscript>
  <iframe src="https://{instance}/statuses/{status-id}/embed" width="100%" height="400" frameborder="0" loading="lazy" title="Post by @{user}@{instance}" />
</noscript>
```

An example:

<div class="yonder-embed" data-status="117535037587509607"><a href="https://manganiello.tech/statuses/117535037587509607/embed">Post by @fabio@manganiello.eu</a></div>
<script async src="https://manganiello.tech/embed.js" charset="utf-8"></script>
<noscript><iframe src="https://manganiello.tech/statuses/117535037587509607/embed" width="100%" height="400" frameborder="0" loading="lazy" title="Post by @fabio@manganiello.eu"></iframe></noscript>

Reactions to the status are fetched from the instance, if the user updates their status the referring page will update as well. If the status is deleted, it will also be deleted from the referring page. And Webmentions towards the Yonder target will also be processed if supported by the referring page, so the referring page will also be shown under the thread as a federated reply.

## How it compares

I want to be honest here rather than hype-y, because "yet another Mastodon-compatible server" deserves scrutiny.

A feature matrix would be the natural way to do this, but matrices are painful to read on a phone, so here's a plain-language summary of where each implementation actually stands (as of late 2026). All of them speak ActivityPub and the Mastodon client API (Yonder implements both the v1 and v2 dialects plus a subset of the Pleroma/Akkoma extensions).

| | Yonder | Mastodon | Akkoma/Pleroma |
|---|:---:|:---:|:---:|
| Language/runtime | Rust (single binary) | Ruby + Node + optional ES | Elixir |
| Required services | Postgres + Redis | Postgres + Redis (+ ES for search) | Postgres (+ ES optional) |
| Mastodon client API | ✅ v1+v2 | ✅ (it's the reference) | ✅ |
| ActivityPub federation | ✅ | ✅ | ✅ |
| Quote posts | ✅ (both FEP-044f and FEP-e232) | ❌ (limited to FEP-044f) | ❌ (limited to FEP-e232) |
| Markdown posts | ✅ | ❌ | ✅ |
| Emoji reactions | ✅ | ❌ | ✅ |
| Webmentions | ✅ both directions | ❌ | ❌ |
| LaTeX math | ✅ server-side | ❌ (only on custom forks, and only on the frontend) | ❌ |
| Account/followers migration (both directions) | ✅ | ✅ | ✅ |
| Data export/import | ✅ both over CSV backups and API crawlers | ⚠️ only CSV backups | ⚠️ only CSV backups |
| Alternative frontends | ✅ installable and configurable on a per-user basis | ❌ | ⚠️ installable on instance level, not customizable on a user level |
| RSS/Atom feeds | ✅ | ✅ | ✅ |
| On-demand fetch of remote content (followers, reactions, replies) | ✅ | ❌ | ❌ |
| Admin panel | ✅ (built-in) | ✅ (built-in) | ⚠️ (as a separate frontend) |
| Battle-testing | new (v1.0.x) | a decade | ~5 years |

## Quickstart

### Docker

Official Docker image provided on [quay.io/yonder/yonder](https://quay.io/yonder/yonder):

docker-compose setup (with Redis, Postgres and separate worker service):

```bash
git clone https://github.com/blacklight/yonder
cd yonder
cp .env.example .env        # set PUID/PGID, domain
cp config.toml.example config.toml
docker compose up
```

### Crate

Or grab the binary directly — it's on [crates.io](https://crates.io/crates/yonder) and in the GitHub releases:

```bash
cargo install yonder-server
# Copy and edit the configuration file
wget -O config.toml https://git.fabiomanganiello.comn/yonder/raw/branch/main/config.toml.example
yonder serve
# Separate process for workers (recommended)
yonder worker
```

### Binary release download

```bash
VERSION="1.0.3"  # IMPORTANT: Set to the version you want
wget -O yonder.tar.xz https://github.com/blacklight/yonder/releases/download/v${VERSION}/yonder-${VERSION}-x86_64-unknown-linux-gnu.tar.xz
tar -xf yonder.tar.xz && cd yonder-${VERSION}-x86_64-unknown-linux-gnu
cp config.toml.example config.toml
./yonder serve
# Separate process for workers (recommended)
./yonder worker
```

## Setup

Config is a single `config.toml` (every key also settable via `YONDER_*` env vars or the admin panel). Federation is on by default, registration modes are configurable, and `yonder config list` dumps every knob.

Create your admin user:

```bash
yonder user create --username alice --admin
```

Or, from your docker-compose directory:

```bash
docker compose run --rm yonder user create --username alice --admin
```

Open the instance, log in, and verify federation works:

```bash
curl 'https://mastodon.social/.well-known/webfinger?resource=acct:you@your.instance'
```

## Try it

- **Source**: [github.com/blacklight/yonder](https://github.com/blacklight/yonder) (AGPL-3.0)
- **Live instance**: [manganiello.tech](https://manganiello.tech) — my own Yonder instance, federated with the wider Fediverse
- **API docs**: `/openapi.json` and `/swagger-ui` on any running instance - e.g. [manganiello.tech/swagger-ui](https://manganiello.tech/swagger-ui)

## AI usage disclosure

In the following table, 🖐️ means "manual" and 🤖 means "aided by AI agents".

| Feature | 🖐️ | 🤖 |
|---|:---:|:---:|
| Initial architecture | ✅ | |
| Feature planning | ✅ | |
| Coding | ✅ | ✅ |
| Testing | ✅ | |
| Code reviews | ✅ | ✅ |
| Deployment | ✅ | |
| User documentation | ✅ | |
| Development documentation | ✅ | ✅ |
| Commit messages | ✅ | ✅ |
| Release notes | | ✅ |
| Translations| | ✅ |
| This blog article | ✅ | |

## Appendix: My personal federated stack

Yonder is the latest product I've built for the Fediverse.

My journey with building products for the Fediverse from scratch rather than contributing only to established projects began around the beginning of this year, as I started growing dissatisfied with the features of many established products.

My main use cases for federated platforms are:

- 📓 **Blogging**
- 🎵 **Music** publishing and federation
- 📢 General-purpose **social media**

And here's how my journey through self-hosted Fediverse platform went over the years.

### Blogging

- Journey: [WriteFreely](https://github.com/writefreely/writefreely) → [**Madblog**](https://madblog.dev)
- [Blog article](https://blog.fabiomanganiello.com/article/Madblog-federated-blogging-from-markdown)
- My instances:
  - [blog.fabiomanganiello.com](https://blog.fabiomanganiello.com) ([**@fabio@manganiello.blog**](https://manganiello.blog/@fabio))
  - [blog.platypush.tech](https://blog.platypush.tech) ([**@blog@platypush.tech**](https://blog.platypush.tech))

Madblog was my starting point to start experimenting building software for the Fediverse.

The use-case was simple: a fully federated blogging platform that ran from a folder of Markdown files.

Single-actor instance, no support for following other users, no timelines, no admin panel, no login, no database, but full bidirectional federation based on text files and email notifications.

### Music

- Journey: [Funkwhale](https://funkwhale.it) → [**Songhive**](https://songhive.org)
- [Blog article](https://blog.fabiomanganiello.com/article/Songhive)
- My instance:
  - [manganiello.music](https://manganiello.music) ([**@fabio@manganiello.music**](https://manganiello.music/@fabio))

I built Songhive to cover many gaps I found in Funkwhale when it came to federation support, and many gaps in existing self-hosted music catalog solutions.

It's a hybrid between a music catalog with support for external sources, a platform for musicians to share and sell their content, and a music social network.

Federation-wise, it offers more features than Madblog (e.g. following users and managing timelines), but its main goal is not to provide all the features that Mastodon provides - just a sensible subset that makes it easy to share music and audio activities.

### Social media

- Journey: [Mastodon](https://joinmastodon.org) → [Akkoma](https://akkoma.dev) → [**Yonder**](https://manganiello.tech)
- My instance:
  - [manganiello.tech](https://manganiello.tech) ([**@fabio@manganiello.tech**](https://manganiello.tech/@fabio))
