My Website Is My Fediverse InstanceApril 27, 2026Luis Quintanilla My Website Is My Fediverse Instance Personal sites as social hubs, protocols as spokes Fediforum April 2026 Note: 0-1 min. Say: "Hi, I'm Luis. This is a story about turning my personal website into a Fediverse-native publishing node without running a full Mastodon instance." Say: "The bigger claim is not that everyone should hand-roll ActivityPub. The claim is that personal websites are already social infrastructure, and protocols can make them interoperable without asking us to move our identity somewhere else." Transition: "I want to start with the least technical part: the web itself." --- The web was already social People, links, feeds, replies, bookmarks, domains, archives. Note: 1-2 min. Say: "In Social Web conversations, we sometimes talk like the social web is a separate thing from the web. I don't think that's right." Say: "People use the web to learn, create, organize, argue, collaborate, share, and build community. That is already social." Say: "The interesting question is: can we add richer social vocabulary to the web without replacing the web with another app-shaped silo?" Transition: "That is why my starting point is not ActivityPub. It is the personal website." --- ## Start as a website Already useful Permanent URLs Posts and notes RSS feeds Bookmarks and replies Searchable archive Then add capabilities Webmentions Microformats ActivityPub Future protocol adapters Native client experiences Note: 2-3 min. Say: "The FOSDEM Social Web reflection that frames this talk is: start as a website, add social capabilities as components." Say: "That makes the path more approachable. Your site still works as a site. It just gets progressively better at speaking social protocols." Say: "This is also important for cost and maintenance. A static website is cheap and durable. The question becomes: what is the smallest dynamic layer needed to participate?" Transition: "IndieWeb gives us a name for the publishing pattern." --- ## IndieWeb in one slide Publish on your own site first. Use your domain as the stable home for your identity and content. Syndicate elsewhere when useful, and receive responses back when possible. Vocabulary POSSE RSS Webmention Microformats Note: 3-4 min. Say: "POSSE is Post on your Own Site, Syndicate Elsewhere. The site is the canonical copy." Say: "RSS lets people subscribe. Webmention lets sites notify each other. Microformats give posts machine-readable shape: author, content, reply target, like target, bookmark target." Say: "That already looks like social infrastructure. It just does not always look like a modern social app." Transition: "My first version of this was classic POSSE." --- ## One identity, many post types lqdev.me identity Articles Notes Responses Bookmarks Reviews Media RSVPs Note: 4-5 min. Say: "One of the big FOSDEM themes that resonated with me was one identity, many post types." Say: "Instead of microblogging identity over here, photo identity over there, video identity somewhere else, review identity somewhere else: what if one account is where the content originates, and different clients consume the parts they understand?" Say: "That is how I think about my site. Articles, notes, responses, bookmarks, media, reviews, RSVPs: all from one identity." Transition: "Before ActivityPub, I was already pushing pieces of this into Mastodon." --- ## My first setup: POSSE to Mastodon Website canonical post RSS new item Logic App Mastodon Original pattern: RSS feed triggers Azure Logic Apps, which POSTs to the Mastodon REST API. Note: 5-6 min. Say: "The first version was simple and worked well. My website published the canonical post. RSS exposed updates. Azure Logic Apps watched the feed and posted to Mastodon." Say: "This is a very practical bridge. It gave me reach without moving the canonical copy." Transition: "But there was a catch: Mastodon was still the social runtime." --- ## What POSSE solved Good Site stayed canonical RSS was simple Automation was cheap Followers saw updates No manual cross-posting Not enough Mastodon was still the account The post was often just a derivative status Interactions stayed elsewhere I still maintained an instance Platform API shaped the experience Note: 6-7 min. Say: "POSSE preserved ownership of the canonical content, but it did not fully preserve ownership of the social identity or interaction surface." Say: "The Mastodon instance still mattered. It was where the social account lived, where follows lived, where notifications lived, and where federation operations happened." Transition: "And running that instance had a cost." --- Hosting is hard after provisioning The first deploy is not the whole story. Note: 7-8 min. Say: "This is one of the big FOSDEM Social Web points that stuck with me. Getting Mastodon running is not necessarily the hardest part. The harder part is everything after provisioning." Say: "Disk fills up. Federation cache grows. Upgrades happen. Database migrations happen. Monitoring happens. Moderation and abuse handling can happen." Say: "For a single-user instance, those costs are not amortized across a community. I still want to participate in the Fediverse, but I do not want to pay the full maintenance tax of running Mastodon just for myself." Transition: "That led to a different question." --- ## The pivot If my needs were... Fediverse identity + followability + post delivery ...could my website provide those directly? Note: 8-9 min. Say: "This was the pivot inspired by Maho's static-site ActivityPub series." Say: "I looked at what I was actually using my Mastodon instance for: a Fediverse presence and a way to get website posts into followers' timelines." Say: "If my site could expose discovery, an actor profile, an outbox, an inbox for follows, and signed delivery, then maybe I did not need a whole Mastodon instance for my personal use case." Transition: "Before the architecture, here's the small amount of vocabulary needed." --- ## ActivityPub vocabulary For humans Account: followable identity Profile: actor document Post: object or activity Timeline delivery: signed POST to inboxes For the protocol WebFinger: account discovery Actor: identity + public key Outbox: published activities Inbox: received activities Note: 9-10 min. Say: "For newcomers: a Fediverse server has to answer a few questions. Who is this account? Where is the profile? What have they published? Where do I send a Follow? How do I know a message was really sent by that actor?" Say: "WebFinger resolves the account name. Actor JSON describes the profile and public key. Outbox lists published activities. Inbox receives follows and other activities. HTTP signatures prove identity for federation." Transition: "The first identity step was making my domain resolve." --- ## Domain identity @lqdev@lqdev.me search handle WebFinger account lookup Actor profile JSON Note: 10-11 min. Say: "The handle is not magic. A server looks up acct:lqdev@lqdev.me through WebFinger and gets back the ActivityPub actor URL." Say: "This was a key mental shift for me. Instead of my website pointing to my Mastodon account, my domain could become the entry point for my Fediverse identity." Transition: "Then the site could become more than a discovery alias." --- ## The site became the actor The key step was not cross-posting harder. It was making the website itself speak enough ActivityPub to be followed. Enough means WebFinger Actor Outbox Inbox Signatures Delivery Note: 11-12 min. Say: "The website did not become Mastodon. It became a small, single-purpose Fediverse participant." Say: "This distinction matters. Mastodon is a full social application. My site is a publishing hub that speaks enough protocol to be discoverable, followable, and deliver posts." Transition: "The architecture follows from that narrower goal." --- ## Static-first, dynamic at the edges Markdown site content F# build HTML, RSS, AP JSON Static CDN cheap, cacheable reads Functions WebFinger, actor, inbox, outbox proxy State Table + Queue followers, delivery Key Vault signing keys not in source code Fediverse Note: 12-14 min. Say: "The core architecture is static-first. Markdown goes into the F# build. The build emits HTML, RSS, ActivityPub activities, activity files, and outbox pages." Say: "Most reads are static files behind Azure Static Web Apps and CDN. The dynamic layer exists only where the protocol requires it: POST inboxes, signatures, correct ActivityPub content types, delivery queues, and persistent follower state." Say: "That keeps the architecture closer to a static site than to a continuously running social server." Transition: "Here's what happens when I publish." --- ## Publish flow Write markdown Build F# generator Deploy Static Web Apps Queue recent Create activities Sign + POST to follower inboxes Timeline native Fediverse post JSON static Note: 14-15 min. Say: "On publish, the build generates the website and ActivityPub data. GitHub Actions deploys the site and queues recent Create activities." Say: "A delivery worker signs those activities and POSTs them to follower inboxes. Shared inbox optimization means a server with many followers can get one delivery instead of one per follower." Say: "This is not a long-running Mastodon replacement. It is a publish-and-deliver pipeline." Transition: "The important bit is that the generated activities preserve intent." --- ## Native syndication IndieWeb intent note article reply reshare star bookmark media review Fediverse shape Note Article inReplyTo Announce Like Link attachment media attachment review metadata Note: 15-16 min. Say: "Native syndication means more than copying text. If a post is a reply, it should be a reply. If it is a reshare, it should be an Announce. If it is a star, it should be a Like." Say: "The site remains the source of truth, but the target platform should receive something that feels native to that platform." Say: "This is where the IndieWeb data model and ActivityStreams vocabulary start to reinforce each other." Transition: "Here is the actual demo path I would use." --- ## Demo path Show the source ```yaml title: "..." response_type: reshare targeturl: https://... tags: ["fediverse","indieweb"] ``` Markdown is still the authoring source. Show the protocol ```json { "type": "Announce", "actor": "https://lqdev.me/api/activitypub/actor", "object": "https://..." } ``` ActivityPub JSON is generated from site semantics. Note: 16-18 min. Say: "For the demo, I would keep it short and concrete." Say: "First show the actual page on lqdev.me. Then show the markdown frontmatter. Then show the generated JSON. Then show WebFinger, actor, and outbox endpoints." Say: "The point is not to teach the whole ActivityPub spec. The point is to show that the site has enough protocol surface to be legible to Fediverse software." Transition: "And the cost profile is the reason this is viable for a personal site." --- ## Low-cost operating model Move work to build time Generate HTML Generate RSS Generate activities Generate outbox pages Cache aggressively Use runtime only for edges Follow requests HTTP signatures Delivery fan-out Follower state Correct AP headers Note: 18-19 min. Say: "The cost model is: do expensive or repeatable work once at build time, then serve static files whenever possible." Say: "Azure Functions only handle protocol edges. Table Storage stores followers and delivery state. Queue Storage handles fan-out. Key Vault stores signing keys." Say: "For my usage pattern, this is cents per month instead of paying for a continuously running single-user Mastodon instance." Transition: "This is working, but it is intentionally not a complete social app." --- ## What is still missing? Product gaps Reply inbox UX Notifications DMs Better migration story Conversation views Protocol/community gaps Client rendering differences Moderation ergonomics Abuse handling Multi-protocol drift Consent boundaries Note: 19-21 min. Say: "The current model is mostly publishing-oriented. People can follow and receive posts, but I still need better ways to receive replies, notifications, and other interactions back into my site." Say: "Webmentions are one possible bridge back. ActivityPub replies could become Webmentions or an owned notification feed. That is still design work." Say: "Moderation and abuse are also real. A personal node is smaller than a community server, but it is still participating in public networks." Transition: "The broader model is hub and spokes." --- ## Hub and spokes lqdev.me source of truth RSS ActivityPub AT Protocol Nostr Webmention HTML Search Note: 21-22 min. Say: "The durable model is hub and spokes. The site is the hub: identity, archive, source of truth. Protocols are spokes: RSS, Webmention, ActivityPub, AT Protocol, Nostr, whatever comes next." Say: "This is not about one protocol winning. It is about not needing to reset identity and content every time a new network becomes important." Transition: "So I want to end with a discussion question." --- I want people to meet me where they are. I do not want my identity to live wherever they happen to meet me. Note: 22-23 min. Say: "That is the central design principle." Say: "If someone follows from Mastodon, great. If they read through RSS, great. If someday they see the same post through AT Protocol or Nostr, great." Say: "But my home, identity, and archive should not depend on any one of those networks." Transition: "Let's discuss." --- ## Discussion What should personal-site-native social interaction look like? Is the inbox a Webmention endpoint, an ActivityPub inbox, email, a feed reader, a dashboard, or all of the above? Note: 23-25 min. Ask: "What feels right or wrong about this architecture?" Ask: "For Fediverse practitioners: what am I underestimating about moderation, identity, delivery, or client compatibility?" Ask: "For IndieWeb folks: what is the right way to pull interactions back to the site without turning the site into a giant app?" If time is short, end here. If there is more time, go to the appendix sections. --- ## Appendix Technical deep dives A. Endpoint anatomy B. Static-first details C. Delivery pipeline D. Native content mapping Strategy deep dives E. Cost model F. Mastodon migration G. Multi-protocol future Note: Appendix index. Use the down arrow on appendix section slides for technical subslides. --- ## Appendix A: Endpoint anatomy What does the site expose so Fediverse software can understand it? -- ## WebFinger ```text GET /.well-known/webfinger?resource=acct:lqdev@lqdev.me ``` Returns account discovery data pointing to the ActivityPub actor. This is what makes `@lqdev@lqdev.me` searchable from Mastodon-style clients. -- ## Actor ```text GET /api/activitypub/actor Accept: application/activity+json ``` Returns the followable profile document: id, preferred username, inbox, outbox, followers, following, and public key. The public key lets remote servers verify signed outbound activities. -- ## Outbox ```text GET /api/activitypub/outbox GET /api/activitypub/outbox?page=1 ``` The root outbox is an `OrderedCollection`. Pages are `OrderedCollectionPage` documents with generated activities. Pagination keeps the outbox compatible as the site grows. -- ## Inbox ```text POST /api/activitypub/inbox ``` Receives Follow and Undo activities. Verifies HTTP signatures, stores follower state, and sends Accept activities back to the remote actor. The current implementation is intentionally narrow: publishing and follows first. --- ## Appendix B: Static-first details The site stays static by default; only protocol edges become dynamic. -- ## Build-time outputs - HTML pages for people. - RSS feeds for feed readers. - ActivityPub activity JSON for Fediverse software. - Outbox root and paginated outbox pages. - Individual activity files with stable hash-based IDs. - Delivery queue metadata for recent posts. The F# generator does the repeatable work once during build. -- ## Runtime edges - WebFinger and actor endpoints need correct JSON/content-type responses. - Inbox needs to accept POST requests. - Delivery needs signing and retry behavior. - Follower state needs persistence. - Activity dereferencing needs an HTTP proxy because Azure Static Web Apps separates static content from Functions. -- ## Why the proxy exists Static activity files live at: ```text /activitypub/activities/{hash}.json ``` Fediverse clients fetch: ```text /api/activitypub/activities/{hash} ``` The Function fetches the static JSON from the CDN, returns `application/activity+json`, caches it, and unwraps `Create` activities to `Note` or `Article` objects for Mastodon URL-search compatibility. --- ## Appendix C: Delivery pipeline How a new website post reaches follower inboxes. -- ## Publish sequence 1. Write markdown. 2. Push to `main`. 3. GitHub Actions builds the F# site. 4. Build generates ActivityPub JSON. 5. Azure Static Web Apps deploys static content and API Functions. 6. Workflow queues recent Create activities. 7. Delivery worker signs and POSTs to follower inboxes. -- ## Shared inbox optimization If 100 followers are on the same Mastodon server, naive delivery sends 100 POST requests. Shared inbox delivery can send one POST to the server's shared inbox. The queue groups followers by `sharedInbox` when available, falling back to individual inbox URLs. -- ## State tables - `followers`: actor URL, inbox, shared inbox, display name, follow activity. - `deliverystatus`: per-activity delivery attempts and outcomes. - Queue messages: pending delivery work with retry behavior. The website remains static, but federation state lives in cheap table/queue storage. --- ## Appendix D: Native content mapping How site semantics become ActivityStreams semantics. -- ## Response mapping | Site intent | Site metadata | ActivityPub shape | | --- | --- | --- | | Reply | `response_type: reply`, `targeturl` | `Create` + `Note.inReplyTo` | | Reshare | `response_type: reshare` | `Announce` | | Star | `response_type: star` | `Like` | | Bookmark | `response_type: bookmark` | `Create` + `Note` + `Link` attachment | -- ## Web-wide responses The target URL can be any URL: - A Fediverse object. - A blog post. - A news article. - A video. - A GitHub issue. If the target is ActivityPub-discoverable, clients can do richer threading or notifications. If it is not, the semantic link still points back to the open web. -- ## Media and reviews Media uses `Note` plus typed attachments because that renders more reliably in Mastodon/Pixelfed-style clients than standalone `Image` or `Video` objects. Reviews can carry Schema.org-flavored rating and item metadata, preserving more of the site's structured content. The principle: prefer native client behavior, but keep the site as the canonical source. --- ## Appendix E: Cost model Why this is cheaper than running a single-user Mastodon instance. -- ## Cost levers - Static CDN serves almost all read traffic. - Build-time generation avoids runtime rendering. - Functions run only on protocol requests. - Table Storage stores small follower/delivery records. - Queue Storage smooths delivery fan-out. - Key Vault stores signing keys without committing secrets. The architecture pays for small edges, not a full always-on social app. -- ## The real comparison This is not a replacement for community Mastodon hosting. It is a replacement for the pieces I personally needed from a single-user instance: - Fediverse identity. - Followability. - Publishing into follower timelines. - Domain-owned archive and canonical content. --- ## Appendix F: Mastodon migration Moving identity is not only a protocol problem. -- ## Migration checklist - Export the Mastodon archive. - Preserve bookmarks. - Preserve follows, ideally as OPML/RSS subscriptions where possible. - Communicate the new canonical Fediverse handle. - Decide what old profile and redirects should say. - Rebuild notification habits outside the Mastodon UI. -- ## What I would miss The timeline is not just infrastructure. It is discovery, ambience, and social context. Replacing a single-user instance with a website removes maintenance burden, but it also removes an app experience. The open question is which parts should come back as site-native tools, feed-reader workflows, or protocol bridges. --- ## Appendix G: Multi-protocol future The point is not ActivityPub maximalism. -- ## Spokes, not new homes - RSS for subscription. - Webmention for website-to-website notification. - ActivityPub for Fediverse follow and delivery. - AT Protocol for data-repo and handle-oriented social applications. - Nostr for key/event/relay-based publishing. The source model should live in the site, not in each adapter. -- ## Design risk Every protocol has its own vocabulary and client expectations. If each adapter grows its own model, the site becomes a pile of bespoke bridges. The better direction is a shared internal content/social model that can project into protocol-native shapes. -- The site is the home. Protocols are ways to be a good guest elsewhere. Note: Final appendix close. Say: "That is the story I want the architecture to tell." ResourcesFOSDEM 2026 Social Web thoughtsWebsite now natively posts to the FediverseImplement ActivityPub on a static site series by maho.devPOSSE to Mastodon using RSS and Azure Logic AppsHTTP Signature Verification and Migration PlanningWebmentions are back thanks to GitHub CopilotActivityPubIndieWeb POSSE