Stefano Marinelli - littleFedi
Barista at BSD Cafe and illumos Cafe - @stefano@bsd.cafe / @stefano@illumos.cafe
Spreading weather forecasts all over the Fediverse via FediMeteo - @admin@fedimeteo.com
Testing littleFedi here on littleOne, its first instance open to outside users. Small ActivityPub server, single Go binary, still in active development.
I will also use this account to provide information about this instance and the development of littleFedi.
Hello from the other side!
Yes, it's true. This instance is now running from the Orange PI PC (NetBSD, armv7). It's currently using the SD Card. The performance is...you judge! And it's not set to low_power mode!
littleFedi: a Fediverse Server That Doesn't Need a Data Centre
I was fifteen, and there were no BBSes in my city. So every call was long distance, once a day, sometimes twice. I'd start the dialer and wait for that sound - the handshake, the negotiation, the hiss settling into a carrier - and then I was connected to a computer sitting in somebody's bedroom, a few hundred kilometres away. I was a co-sysop of a local board and a national moderator of a FidoNet area. None of my friends understood what I was doing, and they'd stopped asking to avoid an incomprehensible monologue. But I liked it, and that was enough for me.
Here's the thing about that computer in someone's bedroom. There was no data centre. No domain, no certificate authority, no hosting provider, no cloud. Just a machine, a phone line, and a person who'd decided to run it. If you wanted to reach it, you called it.
Now look at what it takes today to put a small server on the network so other people can talk to it. A public address, which most home connections no longer have. A domain, which you rent. A certificate, which somebody has to issue you. And, increasingly, a VPS somewhere, because the software won't fit on the hardware you already own.
We've added a lot of infrastructure between two people who just want to talk. That's what littleFedi is about.
What it is
A single Go binary. No Ruby, no Sidekiq, no Redis, no separate worker processes to babysit. You run init, answer a few questions, and you've got a working instance. It speaks ActivityPub, and it speaks the Mastodon client API well enough that existing apps just work.
It also runs on hardware that would make Mastodon - or even Akkoma - struggle. Most software in this space assumes a VPS with a few gigabytes of RAM and a database server next to it. We assumed a Raspberry Pi Zero W behind a home router. There's a low_power mode that tunes memory use, image decoding and thumbnail generation for exactly that kind of box, and it's tested on that kind of box, not just on a fast dev machine.
In spirit this puts littleFedi close to snac, which I've always liked a lot. Same conviction: a personal server shouldn't need a fleet of services behind it.
Federating without a public address
littleMesh is the part I'm most attached to, and it's the part that goes back to the modem.
Your instance generates an Ed25519 key pair. That key is its identity - the node's address is derived from the public key, so reaching that address means reaching the holder of that key and nobody else. No registrar, no certificate authority, nobody to ask permission from.
A small set of public lighthouse nodes help two instances find each other. Once they're introduced, the traffic runs over a second TLS session pinned to both node IDs. The lighthouse copies encrypted bytes back and forth. It never sees plaintext, and it can't impersonate either side. And if the two nodes can reach each other directly, they drop the relay after the introduction and talk peer to peer.
Which is, more or less, calling the BBS directly. Just without the phone bill.
The gateway into ordinary HTTPS
Mastodon and other regular servers can't resolve a mesh address on their own. There's no domain and no certificate for them to find.
That's what the optional HTTPS gateway is for. A lighthouse operator can run one alongside the relay, and it bridges the mesh into ordinary HTTPS for the rest of the web. The gateway has to terminate TLS to do that, so it can technically see the traffic passing through it. Which is exactly why it's a separate, opt-in piece and not something every node exposes by default.
It has two independent settings: one controls what the gateway lets ordinary internet visitors reach at all, and a second one applies again at the destination node. Left at their defaults, both allow only federation traffic - ActivityPub delivery, discovery, public media. Web login, API and media proxy stay closed unless an operator deliberately opens them.
Mesh peers talking to each other directly never touch the gateway at all. That exposure only applies to the bridge into the wider web. And all of this can be self-hosted.
Chronological timelines
Timelines are chronological. Nothing gets reordered by an engagement model.
If you want something closer to "what did I miss", there's a separate /catchup page you visit on purpose. It ranks posts using signals your own instance already has - how many people you follow boosted something, whether it continues a conversation you took part in. No external popularity score, no telemetry, nothing leaves the machine. You press "mark as read", it moves a divider, and that's the only thing it remembers.
Self-expiring posts
You can set a post to expire, with its own timer, instead of a fixed instance-wide setting.
This isn't a client-side trick that hides the post from view. The expiry goes on the same durable job queue that runs the rest of littleFedi's background work, so the deletion survives restarts and isn't lost if the process happens to be down at the moment the timer fires. When it does fire, the post is deleted and a real Delete activity goes out to everyone who received it - so it actually disappears from remote instances too, not just locally. Editing the post before then can push the timer back or cancel it.
Static blogs, with real threaded replies
littleFedi can take a Fediverse post and publish it as a page on a plain static blog, with its own Atom feed and permalinks that don't move even if you edit the post later. No JavaScript, no database hit on page load.
The part I find more interesting is that the replies aren't left out. If the author turns the option on, littleFedi pulls the public replies that were actually federated to the post, threads them the same way the timeline does, and bakes the whole tree into the generated HTML at build time. So a blog post can show a real comment thread, in the same static file, with the same guarantee as the rest of the page - no JavaScript, no live queries. Only public and unlisted replies qualify, obviously. Anything followers-only or direct never enters the picture.
Why it looks like this
This isn't minimalism for its own sake. It's about how many people simply can't run their own server today, because the requirements are too steep. The hardware, the ops complexity, or just needing a domain and a public address before you can start. We're trying to remove those barriers one at a time, while still shipping a real, federating, reasonably complete server: polls, quotes, scheduled posts, MFA, PostgreSQL and S3 if you want to scale up later.
I've written before about taking a semi-truck to buy salad. Hardware keeps getting more expensive and the software running on it keeps asking for more of it every year. That's backwards. If the machines cost more, the operational cost of what sits on them should go down, not up. Same with complexity: the default direction is to keep adding it, and we'd rather strip it out.
And there's the other half, which is closer to why any of us are doing this at all. It's the same thing that drew me to snac and to the way grunfink works on it, and the same thing that had me dialing a stranger's computer at fifteen. People building tools so that people can talk to each other. Nothing more dressed up than that. We'd rather show the servers running, talk about the Pi sitting in the corner, share a tiramisu photo if it comes up. The joy in this was never about the money it brings in. It's about what we end up building, humanly, because of it.
It's beta software, still short of a first release, and I'd rather say that plainly than oversell it. But it runs, and it federates. That's the part I wanted to write about.
Hi everyone, I'm Stefano
Also known as the BSD Cafe and illumos Cafe barista - @stefano@bsd.cafe and @stefano@illumos.cafe
This is the first post from littleOne (littleone.littlefedi.social), the first littleFedi instance open to outside users.
littleFedi is a new ActivityPub server, still in active development, written in Go and shipped as a single binary. It speaks standard ActivityPub, so it federates normally with Mastodon, snac, GoToSocial, Akkoma and the rest of the fediverse, and it exposes a Mastodon-compatible API, so most existing apps already work with it.
A few things about it that aren't the usual fediverse defaults:
-
Catch-up instead of an algorithm. Timelines stay chronological, full stop. There's a separate
/catchuppage, visited on demand, that ranks what you missed using only signals this instance already has locally - who you follow boosted it, replies and favourites delivered here, hashtags you follow. No external popularity data comes in, nothing about what you read is tracked. It answers "what did I miss" without turning into a feed that decides for you. -
Static blogging built in. Any post can be marked as a blog post and gets published as a plain static page under
/@username/blog/, with its own permalink, Atom feed, and no JavaScript or database hit per view, while still being a normal federated post underneath. A proper home for longer writing that doesn't need to compete with a timeline. -
Self-expiring posts. Any post can be given a timer and auto-delete on its own.
-
Bubble timeline. A middle ground between local and federated: a timeline scoped to a set of instances you've chosen to group together, not just your own or everything.
-
littleMesh. A way to federate without a public domain, certificate, or open port at all - meant for something like a Raspberry Pi behind NAT. Instances get an address derived from an Ed25519 key pair and reach each other through pinned relays that never see plaintext.
-
No trends, no suggestions. These are intentionally left empty. Nothing here is trying to surface "popular" content or keep anyone scrolling longer.
-
Security defaults taken seriously. Signed federation (HTTP Signatures), optional Object Integrity Proofs, TOTP MFA, audit logs, and full account export, migration and deletion if you ever want your data to live somewhere else.
This instance is here to test all of that with real accounts, not just a small group ones'. In the next few days I'll be reaching out to everyone who already told me they were interested, to set the first accounts up - an invite is coming. If you'd rather just follow along and see how it goes, that works too.
It's a test instance, so expect the occasional rough edge. If something breaks or feels wrong, tell me - that's exactly what this phase is for.
@epn4littlefedi Bubble timeline will merge the local timeline and the timelines of the instances that the admin will set as "bubble". At the moment, it will merge the local posts and the BSD Cafe and illumos Cafe (known) posts.
It needs some works as it's quite slow, it probably needs one more db index.
@pluvialgeist yes, it’s already supported. When you export your data from a littleFedi instance, the blog is already a part of it and can be reimported.
I’m also planning to add a “export to BSSG” feature (https://bssg.dragas.net)
Hello from the other side!
Yes, it's true. This instance is now running from the Orange PI PC (NetBSD, armv7). It's currently using the SD Card. The performance is...you judge! And it's not set to low_power mode!
Still here, still enjoying littlefedi.
It sounds like it moved onto a SBC running NetBSD which is exciting!
I just adjusted my relay instance which now also finally supports #GoToSocial! Of course, it also supports Pleroma, snac, Mastodon, littlefedi, starling and many other ones!
With relays, your own posted content gets distributed to all connected instances, as well you get the content all other instances. Currently, mostly tech related instances are connected, focusing on #Linux, #Proxmox, #BSD / #FreeBSD, #IPv6 and many other things!
More information at: https://fedi-relay.gyptazy.com
#socialmedia #fedi #fediwall #fediverse #activitypub #activitypubrelay #relay #social #snac #snac2 #mastodon #gts #gotosocial #littlefedi #pleroma #misskey #services #devops #starling #tech
How background workers work in littleFedi
Every littleFedi instance runs a background job queue. Jobs are split by kind, but they all share one thing in common: they sit in a database table and are executed by the "main" worker pool, whose size you control with queue.workers (default min(8, GOMAXPROCS), 1 on the low_power preset).
The kinds fall into two groups:
-
Heavy, mostly CPU/DB-bound work - inbox (ActivityPub signature verification, actor fetches, home-feed fan-out) and media_cache (image decoding). These block a worker synchronously while they run.
-
Light, mostly network-bound outbound work - delivery (one signed POST to one remote inbox), its delivery_fanout expander, push_notification, and send_email. These are short and often latency-sensitive: a boost that hasn't landed yet or a push that hasn't arrived is visible to real people.
By default every worker can pick up any kind of job. That is perfectly fine for most instances. The only caveat: job priority only orders queued rows, it cannot preempt a job that is already running. So if a slow inbox or media job is occupying the single (or few) workers, timely outbound delivery, push and email can end up waiting behind it.
light_workers (default 0, disabled) spins up a second, dedicated worker pool for exactly those four light outbound kinds. It is a strict either/or, not extra capacity: with light_workers > 0, delivery, delivery_fanout, push_notification and send_email run only on this pool. The main pool stops touching them, even when idle, and there is no overflow between the two. So workers=8 + light_workers=2 gives outbound federation exactly 2 workers, not 10.
The light pool also yields to interactive requests like the main one does, but with a shorter wait (3s vs 10s) when both compete for the single foreground-recovery slot - so short, people-visible outbound jobs win that one job while every other worker keeps yielding to keep the web UI responsive.
It's totally optional.
With 0 (the default) all four kinds stay on the main pool. The extra goroutine(s) cost is negligible even on constrained hardware.
It can be useful for:
-
low_power devices (e.g. Raspberry Pi or similar): keep workers=1 for the heavy inbox/media work and enable light_workers=1 so outbound delivery, push and email keep flowing even while your single main worker is blocked on a slow inbox job. This is the recommended combination on a small box.
-
Instances where inbox/media loads spike: a burst of incoming activity (a big follower purge, backlog of signature-verification work) can stall time-sensitive outbound delivery on a shared pool; giving the light kinds their own pool decouples them.
-
Visibility matters: push notifications and federation delivery are things users notice immediately; if you care about their latency on a busy instance, the dedicated pool is a cheap way to protect it.
Running a single pool is the right default for most instances. Also note both pools share the DB connection limiter (sized from MaxOpenConns): the database is the serial resource, so worker counts beyond the connection count buy nothing, extra workers just deepens the queue in front of it. Size light_workers for your real outbound throughput.
@mboelen I think it's also related to the Wireguard tunnel MTU, as the CPU load is quite low. I'll probably re-point the DNS to make it more efficient
If you see it's slower, consider it's being tunnelled via Wireguard without a MTU tweaking
@the_coffee_lover@beige.party it will be released as soon as it will be more "battle tested". Meanwhile, I can send you an invite code to test it here