Two Fediverse Servers in One Night
Forty years of internetworking, two decades of false starts, and one night with a prompt window.
The tools caught up before the committees did.
I have been building internetworking software for forty years. I was writing protocol implementations before the Web existed. I have mass-market shipping code in products you have used. I have mass-market shipping code in products you have never heard of that power things you use every day.
I was a Usenet admin. I was on LiveJournal before it was fashionable and stayed after it wasn't. I watched social media happen to the internet. I am on a first name basis with the nearly forgotten dev who wrote Twitter mostly by himself, and with the people who created OpenID and OAuth and OIDC. I am a known face at IIW. I was a runner-up to be the Executive Director of Bluesky. (Those were some of the most fun job interviews I have ever had.) I have strong opinions about Bluesky, its protocol, and what it should have been.
I have a long and complicated history with federated protocols. OStatus. Diaspora. pump.io. Half a dozen others that never escaped their README files. I was in the forums where ActivityPub was specified. I attended the W3C Social Web Working Group calls. I have been to IIW more times than I can count, watching the same conversations recur with different proper nouns.
I have written half-done social media stacks nearly a dozen times. Never quite pulled over the line, before I ran out of energy, time, or pain tolerance. None of it shipped. Not for me.
The protocols shipped. Other people's implementations shipped. But every time I tried to build something on top of them, something got in the way. Scope creep. Committee politics. A reference implementation that became a de facto monopoly. The spec changing under my feet because one large deployment decided it worked differently.
I have a seething hatred of how Mastodon is constructed.
This is not about Gargron personally. (He seems like a genuinely nice person.) This is about the fact that a Ruby on Rails monolith with Sidekiq and Redis and PostgreSQL and ElasticSearch and a Node.js streaming server became the definition of "how to run a fediverse instance." The Mastodon Client API is not a standard. It is an accident of market share. The ActivityPub federation is not the spec, it is whatever Mastodon does, and if your implementation is technically correct but Mastodon doesn't interoperate, you are the one who is wrong.
The result is that running a fediverse server means running Mastodon, and running Mastodon means operating a distributed system with six moving parts, written in a language that treats memory as literally free but has no idea what a thread is, 400,000 lines of code, and a dependency tree that requires a full-time SRE to keep healthy. The "instance admin" model makes every operator a feudal lord responsible for the conduct of their peasants, with the threat of defederation as the enforcement mechanism. The median instance is one person who wanted to post, not run a daycare.
I tried to build something simpler. Multiple times. I never finished. The protocols are too fiddly. The signature schemes are underspecified. The test vectors didn't exist. The reference implementation disagreed with the spec and everyone deferred to the implementation. The implementation disagreed with itself.
Last night I sat down with a prompt window and everything I had ever written for 25 years about this problem.
This morning I had two working servers.
Broadside
Broadside is a one-way ActivityPub server for organizations. It solves one problem: letting an organization publish to the fediverse without running Mastodon.
You get federated identities like @announcements@corp.example. People follow from any ActivityPub client. The organization publishes. There is no inbound content processing, no moderation queue, no timeline, no notifications.
Four ingestion methods: CLI, RSS polling, webhooks, directory watching. One binary. One config file. SQLite. Deploy behind Caddy or nginx, point DNS, done.
What it does not do: no Mastodon Client API, no OAuth dance, no web UI for posting, no reply/like/boost processing, no admin dashboard.
4,315 lines of Rust across 20 source files. I can read the entire codebase in an afternoon. The security audit took two passes. The pentest findings fit in one commit message.
The design was deliberate. Every feature Broadside does not have is a feature I do not have to secure, maintain, explain, or debug at 3am.
Smallhold
Smallhold is a full bidirectional ActivityPub server with enough of the Mastodon Client API that real clients work. Phanpy. Ivory. Elk. Tusky. Tuba. No modifications required.
One binary. One config file. SQLite. No Redis. No Sidekiq. No ElasticSearch. No Node.js streaming server.
A solo operator runs multiple "personas" under one domain. Each persona is an independent ActivityPub actor with its own keypair, inbox, outbox, and followers. From the fediverse's perspective they are separate accounts that happen to share infrastructure. From the operator's perspective they are rows in a table.
14,121 lines of Rust. 24 database tables. 61 Mastodon Client API endpoints. 11 inbound ActivityPub activity types. Full-text search via Tantivy. WebAuthn passkey login.
This is not a Mastodon replacement. This is not for public signups. This is for one person who wants to participate in the fediverse without operating a distributed system.
What Made This Possible
Not my forty years of experience. That experience told me this was hard. That experience was correct. It is hard. The protocols are fiddly. The signature scheme is underspecified. The test vectors do not exist in sufficient quantity. The reference implementation still disagrees with the spec.
What changed was that I could finally give something the full context.
I sat down with opencode and fed it everything. Three years of AI conversation logs exported from OpenAI and Anthropic, hundreds of conversations where I had already tried to explain this problem. Hundreds of pages of my own text files: notes, rants, false starts, half-finished specs, design documents that went nowhere.
I did not write 18,000 lines of Rust. I reviewed code, pointed at failures, ran test suites, pasted stack traces, read security audits and said "fix this" or "this is acceptable, document it."
I spent the night on architecture, security, product decisions, and verification. I did not spend it on syntax. I read the code. I understand the code. I could modify it by hand. But the bottleneck was never typing. It was knowing what to build. I had spent two decades knowing what to build.
The Receipts
Both servers pass their conformance suites.
Broadside:
WebFinger RFC 7033: 18/18
go-fed ActivityPub compliance: 12/12
Fediverse Pasture edge cases: 93/93
Smallhold:
All of the above, plus
Mastodon Client API: 61/61
Both servers are federated live with mastodon.social. I can post from Smallhold and it appears on the fediverse. I can broadcast from Broadside and accounts follow and receive.
The code is public. Read it yourself. Tell me what I missed.
So What
The fediverse has a Mastodon problem. It is possible to run ActivityPub without running a quarter-million-line Rails monolith with five runtime dependencies. It has always been possible in theory. Now it is possible in practice, for me, overnight.
Broadside and Smallhold work. The argument that you have to run Mastodon because nothing else interoperates is no longer true. The argument that ActivityPub is too complicated for a small team is no longer true. The argument that you need a full-time SRE to participate in the fediverse is no longer true.
These are not demo implementations. I am running them for my own use. The security posture is real. The conformance testing is real. The circuit breakers and retry logic and rate limiting are real.
Forty years of experience got me to the point where I knew what to ask for. One night got me working software.
I am deploying both this week.
Both repositories are at [github.com/MarkAtwood/broadside](https://github.com/MarkAtwood/broadside) and [github.com/MarkAtwood/smallhold](https://github.com/MarkAtwood/smallhold).github.com/MarkAtwood/broadside and github.com/MarkAtwood/smallhold.*

I still use LJ occasionally. The post editor is a great way to bypass YouTube ads.
Just FYI you can almost certainly run broadside locally and have cloudflare tunnel the result to make it publicly visible/accessible. Replacing NGINX with cloudflare is probably about 3 lines of cloudflared configuration