Bonumark Stream v0.8.1 is now available on GitHub and adds optional ActivityPub federation to the self-hosted publishing system.
For the first time, a Bonumark site can participate directly in the fediverse while keeping the site, domain, database, publishing workflow, and content under the owner’s control.
ActivityPub Had to Fit Bonumark
I built Bonumark Stream because I wanted somewhere to publish short posts without making a social platform the center of my publishing.
The idea was simple. I wanted the speed of a social feed on a site I controlled. My posts should live on my domain. My database should remain the source of truth. My archive should not depend on an algorithm, a platform’s business model, or whether somebody else decides the service I use should work differently tomorrow.
That philosophy has not changed. Adding ActivityPub only made sense if federation could fit around that model instead of replacing it. That became the central requirement for v0.8.1.
Bonumark can now participate in the fediverse, but it does not become a fediverse client with a publishing system attached to it. Bonumark remains the publishing system.
ActivityPub is another path in and out.
Publishing Still Happens on Your Site First
One of the most important decisions in the ActivityPub implementation is that federation does not sit in front of normal publishing.
You still write and publish a Stream Post through Bonumark. Bonumark saves that post locally first, and your own database records the publication. Only after that local publication succeeds does Bonumark queue the ActivityPub delivery.
If Mastodon is having a problem, your post still publishes. If another remote server is unreachable, your post still publishes. If federation delivery needs to retry later, the post still exists exactly where it was supposed to exist in the first place.
On your site.
Federation should extend publishing. It should not become a dependency that can prevent publishing.
A Bonumark Site Can Have a Fediverse Identity
When ActivityPub is enabled, Bonumark creates a stable single-owner fediverse identity for the site. WebFinger allows compatible services to discover that identity, and people using platforms such as Mastodon, GoToSocial, Misskey, and other ActivityPub software can follow it.
Bonumark can then federate normal Stream Posts to those followers. That includes new posts, updates, deletion, multiple images, and image alt text. The system also supports follower requests and approval, Follow, Accept, Reject, Undo Follow, and shared inbox delivery.
I tested the implementation directly against Mastodon, GoToSocial, and Misskey.io during development. The goal was not just to make an ActivityPub endpoint respond. The goal was to make Bonumark actually participate.
Following Exists Without Becoming Another Public Feed
Sending posts into the fediverse was only part of the work. If Bonumark was going to participate, I also wanted the owner to be able to follow people without leaving Bonumark every time they wanted to see what those accounts were publishing.
v0.8.1 adds a private frontend Following timeline for that. It is chronological, newest first, non-algorithmic, and free of recommendations. There is no public discovery feed and no attempt to turn Bonumark into another giant social network.
Remote posts from people I follow also do not become part of my public Bonumark Stream. They stay out of public search, the sitemap, static exports, and the public feeds meant for my own content.
My Stream is what I publish. Following is what I privately choose to read. Bonumark keeps those two things separate.
I Can Participate Without Leaving Bonumark
Following is not limited to reading. From Bonumark, the site owner can reply to a remote post, Like or Unlike it, Boost or Unboost it, open a private conversation, or open the original post on its home server.
Replies were especially important to get right because I did not want a separate federation composer creating a second kind of Bonumark content. A reply is still a normal Bonumark Stream Post, and it uses the normal frontend composer.
Bonumark records the reply as local content first, just like any other post. The ActivityPub reply information is attached so federation knows which remote object it belongs to. There is still one publishing system. ActivityPub does not create another one beside it.
The Fediverse Can Interact Back
The connection works in both directions. Bonumark can receive authenticated replies, Likes, boosts, and the corresponding Undo activities from remote actors. Incoming replies begin in moderation rather than immediately appearing as public comments.
Remote Likes and boosts are kept separate from Bonumark’s existing local Like system. A Like from a remote ActivityPub account is not the same thing as one of Bonumark’s anonymous local Likes, and combining them into one number would blur two different participation models. Instead, the owner can privately see fediverse interactions associated with a local post.
Remote actors also remain remote actors. Following somebody on Mastodon does not create a Bonumark account for that person, and receiving a reply does not silently add a new user to the site.
Federation stays federation. Local accounts stay local accounts.
Media Needed to Work Like Real Media
ActivityPub testing exposed how easy it would have been to claim media support without making the result good enough to use.
v0.8.1 handles image-only remote posts, individual images, multiple-image galleries, mixed portrait and landscape images, distinct alt text, video, audio, and content warnings. Content warnings conceal both the text and attached media until the owner chooses to expand them.
Images keep their alt descriptions for accessibility without dumping those descriptions into the visible post as unwanted text. Those details matter once you stop testing federation with a few lines of plain text and start using it against real accounts. The feature needed to work with the content people actually publish.
Deleted Fediverse Posts Stay Deleted
One of the more important architectural decisions in this release involves deletion and republication. A Bonumark Stream Post has a durable local identity, so it can move through draft, publish, unpublish, trash, restore, and republish states while remaining the same local post.
ActivityPub has a different lifecycle. Once Bonumark federates a publication, that publication receives its own ActivityPub generation and object address. If that generation is deleted, Bonumark sends Delete and the old ActivityPub object becomes a Tombstone.
Restoring or republishing the local Bonumark post does not bring that deleted fediverse object back from the dead. Bonumark creates a new ActivityPub generation with a new object address, while the old one stays retired.
Replies, Likes, boosts, and other interaction state remain attached to the publication generation they originally targeted. Deletion should mean something, and a deleted federated object should not silently become live again because the underlying local post was restored later.
Federation Runs Asynchronously
Remote servers fail. Connections time out. Services rate-limit requests. Software goes offline. None of that should turn the Publish button on your own website into a waiting room for somebody else’s server.
Bonumark handles federation delivery asynchronously. The delivery system includes queue claiming, bounded batches, stale-processing recovery, exponential retries, Retry-After handling, dead-letter handling, safe retries, inspection, and repair tools. Delivery can run through normal server cron or Bonumark’s protected web-cron path.
If a remote server is temporarily unavailable, Bonumark can deal with that separately while the local site continues doing its job. Your publishing system should not stop because somebody else’s system did.
Federation Also Created New Security Requirements
ActivityPub means communicating with remote servers and accepting signed requests from systems Bonumark does not control. That could not be treated like an ordinary internal feature.
Bonumark supports both the established RSA HTTP Signature format widely used across the fediverse and RFC 9421 HTTP Message Signatures. Incoming activity is checked for signature validity, digest integrity, actor identity, key ownership, activity identity, duplicate activity, replay attempts, and valid request structure before it can affect federation state.
Private signing keys are encrypted using installation-derived key material, and key creation and rotation include a cryptographic self-test. Remote discovery and delivery also use restricted HTTPS networking designed to reduce server-side request forgery risk. Private, loopback, link-local, reserved, and carrier-grade NAT addresses, along with metadata endpoints, are rejected. DNS behavior, redirects, response sizes, request sizes, JSON depth, and network time are bounded.
Federation necessarily means letting the application communicate with the outside world. It does not mean the outside world should receive unrestricted access to the application.
Pause, Suspend, or Permanently Deactivate Federation
v0.8.1 separates three actions that could easily have been treated as one switch. The owner can pause federation, which temporarily takes the actor and inbox out of service while preserving the identity and relationships. The owner can also suspend delivery, which keeps the actor available but stops Bonumark from claiming outbound deliveries until delivery resumes.
Permanent deactivation is deliberately different. It sends Actor Delete and permanently retires the current actor identity. The actor URL returns 410 Gone, WebFinger stops advertising it, and Bonumark does not currently create a replacement identity.
There is no convenient Undo button after that. If there is any chance the identity will be used again, Pause or delivery suspension exists for that reason. Permanent deletion should actually be permanent.
ActivityPub Is Optional
None of this is automatically turned on because somebody upgrades Bonumark. ActivityPub is disabled by default, and a site owner has to meet the hosting requirements, create the signing key, configure the feature, and deliberately enable federation.
That matters because I do not want federation to become the new definition of Bonumark Stream. Somebody may want a self-hosted microblog and have no interest in the fediverse. That is still a completely valid Bonumark installation.
Someone else may want their Bonumark site to become their fediverse identity. Now it can. The owner chooses.
Upgrading From v0.7.2
The previous public GitHub release was v0.7.2, which concentrated heavily on hosting portability, upgrades, deployment verification, and the operational foundation underneath Bonumark. v0.8.1 builds on that foundation.
Upgrading from v0.7.2 applies migrations 0018 through 0028. Those migrations add the data structures required for ActivityPub identity, signing keys, publication generations, delivery, followers, Following, interactions, blocking, actor retirement, and remote actor lifecycle state.
They do not replace existing Stream Posts or rewrite their bodies. They do not discard Profiles, media, comments, local Likes, themes, imports, exports, or the rest of the owner’s existing Bonumark data. ActivityPub also remains disabled after the upgrade unless the owner chooses to enable it.
The upgrade changes what Bonumark is capable of doing. It does not make the federation decision for you.
Bonumark Still Is Not Trying to Become a Social Network
Bonumark Stream now speaks ActivityPub, but I have no interest in turning it into a smaller clone of Mastodon or another general-purpose social platform.
There is no public federated timeline, no algorithmic recommendation system, no multi-user federation model, and no direct messaging. There is also no requirement that anyone use ActivityPub at all.
The Stream remains centered on what the owner publishes. The database remains the source of truth. The site remains the owner’s publishing home. That is the boundary I wanted v0.8.1 to preserve.
What v0.8.1 Changes
Bonumark Stream started because I wanted to own the place where I published short-form work. v0.6.0 expanded what could exist around that stream through Profiles and a much stronger theme system. v0.7.2 strengthened the operational side of running and upgrading the software across different hosting environments. v0.8.1 lets that same owned publishing system participate directly in the fediverse.
The important word there is participate.
Bonumark does not need to hand publishing over to Mastodon, GoToSocial, Misskey, or any other service in order to communicate with them. I can publish from my site, someone elsewhere can follow that identity, the post can reach them, and they can respond. I can follow people back and participate from Bonumark.
But my site is still home.
That is what I wanted ActivityPub to add. Not another platform I have to live inside, but another open path connecting the platform I already own to the rest of the web.
Bonumark Stream v0.8.1 is available now on GitHub.
New Here?
Read Next:
- Why I Built Bonumark Stream
- Bonumark Stream v0.6.0 Is Here
- Builder Receipt: Bonumark’s Theme Architecture