You can follow this website

~/articles/you-can-follow-website
Animated share card for You can follow this website

Open Mastodon and search for @joe@joehahn.dev. You'll find my website sitting there like a person. Follow it, and everything I publish shows up in your timeline.

No newsletter. No feed reader you forget to open. The site is the account.

That shorthand is wrong in a way worth fixing, though, so let me start there.

Mastodon is not the network

People say "Mastodon" the way they used to say "Kleenex."

Mastodon is one app. The network underneath it is called the fediverse, and the shared language is a published standard called ActivityPub. Any software that speaks it can talk to any other software that speaks it.

Email works the same way. Gmail is not email. Gmail is one company's app for reading it, and you've never needed a Gmail account to write to someone who has one. The protocol is public, everyone implements it, and the apps compete on everything else.

The fediverse has a lot of apps:

  • Mastodon: short posts, the one everybody's heard of
  • PixelFed: photos, roughly Instagram-shaped
  • PeerTube: video
  • Lemmy: link and discussion boards, roughly Reddit-shaped
  • WriteFreely and Ghost: blogs
  • Flipboard: a magazine app that joined in 2024

Someone on PixelFed can follow someone on Mastodon. Neither of them had to sign up for the other thing. That's the entire point, and it's why "my site is on Mastodon" is the wrong sentence.

My site isn't on Mastodon. It speaks ActivityPub. Mastodon users can follow it, and so can everyone using any of the rest.

What that gets you

Two things, and the second is the one I underestimated.

The first is delivery: when I publish, the post is pushed out to everyone following the site, the same way a person's post reaches their followers. Compare that to RSS, which is a pull: your reader wakes up, checks my site, and finds something new. Both work, but push means the post arrives where people already are, instead of sitting on my site waiting for someone to come looking.

The second is that replies come back. Someone answers a post in their timeline, and the reply travels to my site. It's a conversation on their turf and mine at once, with nobody's advertising business in the middle.

There's no company between us in either direction, and if Mastodon vanished tomorrow you could follow this site from PixelFed or Ghost or whatever gets built next year, without a single thing changing on my end.

What it took

A Drupal module, mostly. I installed ActivityPub, and it did the protocol work: the discovery endpoint, the account document, the cryptographic signing that proves a post came from me.

Then five small things, four of which had nothing to do with the fediverse:

  • An "actor", which is the account object. Mine is @joe@joehahn.dev.
  • A signing key, generated by the module.
  • Somewhere safe to keep that key.
  • One permission granted to logged-out visitors.
  • A scheduled job to push posts out.

The whole thing was an afternoon. Most of that afternoon was the boring four.

The parts that bit

The signing key gave me the worst moment. The module writes it to Drupal's private file area, and I hadn't configured where that area is. So it fell back to a relative path and quietly created a folder inside the public web directory. A private key. In the folder the web server hands to anyone who asks.

Nothing was exposed, because I caught it in testing on my own machine. But the fix is to set the private path first, before generating anything, and I'd rather you learn that from a paragraph than from a directory listing.

The permission one is less alarming and easier to trip over. Remote servers fetch your account document as a stranger, with no login. If logged-out visitors can't view profiles, every server that tries to follow you gets a 403 and your account looks broken to everyone but you.

The scheduled job runs hourly on my host. That's my delivery delay: publish a post, and a follower might see it 58 minutes later. Fifteen minutes would be better, but hourly is what the cheap shared hosting gives me, and for a blog nobody is sitting there refreshing, it's fine.

What I'd do differently

The module is version 1.0.0-alpha21, which is alpha software and not covered by Drupal's security advisory policy, so there's no guaranteed disclosure process if somebody finds a hole in it. It also throws deprecation warnings on PHP 8.4 that fill logs and mean nothing. I'd run it on a personal site again. I wouldn't put it on a client's site yet.

It's also a publishing endpoint and not a client. I can't read my timeline in Drupal, and I don't want to. For the human half I have an ordinary account on an ordinary server, which is @drupalthoughts@fosstodon.org.

This is one setup, on one host, tested by me. The delivery has worked every time I've published since, which at this point is a small enough number that I'd call it promising rather than proven.

The part I keep coming back to is that none of this needed permission. I didn't apply to a platform or get approved for an API. I ran an install command, and now my website is a thing you can follow.