**#ActivityPub support in #Madblog**
-
@liaizon @fabio Alas, the PR has been merged, so it'll be a long while until I bother Claire again.

But I'll keep updating my own list. I see in the code where the interaction policy is declared, but not where individual quotes are authorized. If I quote this post here, let's test if both of us will see the quote.
-
@liaizon @fabio Alas, the PR has been merged, so it'll be a long while until I bother Claire again.

But I'll keep updating my own list. I see in the code where the interaction policy is declared, but not where individual quotes are authorized. If I quote this post here, let's test if both of us will see the quote.
@liaizon Yeah, works on my server but not yours.

Hey @fabio, congrats on the ActivityPub support! The quote authorization that my server got from your blog for the above post seems to 404: https://manganiello.blog/ap/actor/quote_authorizations/34bcaca1-62d8-4620-b97d-552008426bce
-
#ActivityPub support in #Madblog
I am glad to announce that Madblog has now officially joined the #Fediverse family.
Madblog has already supported #Webmentions for the past couple of weeks, allowing your blog posts to be mentioned by other sites with Webmentions support (WordPress, Lemmy, HackerNews...) and get those mentions directly rendered on your page.
It now adds ActivityPub support too, using #Pubby, another little Python library that I've put together myself (just like Webmentions) as a mean to quickly plug ActivityPub support to any Python Web app.
Webmentions and Pubby follow similar principles and implement a similar API, and you can easily use them to add federation support to your existing Web applications - a single
bind_webmentionsorbind_activitypubcall to your existing Flask/FastAPI/Tornado application should suffice for most of the cases.Madblog may have now become the easiest way to publish a federated blog - and perhaps the only way that doesn't require a database, everything is based on plain Markdown files.
If you have a registered domain and a certificate, then hosting your federated blog is now just a matter of:
mkdir -p ~/madblog/markdown cat <<EOF > ~/madblog/markdown/hello-world.md This is my first post on [Madblog](https://git.fabiomanganiello.com/madblog)! EOF docker run -it \ -p 8000:8000 \ -v "$HOME/madblog:/data" \ quay.io/blacklight/madblogAnd Markdown files can be hosted wherever you like - a Git folder, an Obsidian Vault, a Nextcloud Notes installation, a folder on your phone synchronized over SyncThing...
Federation support is also at a quite advanced state compared to e.g. #WriteFreely. It currently supports:
-
Interactions rendered on the articles: if you like, boost, quote or reply to an article, all interactions are rendered directly at the bottom of the article (interactions with WriteFreely through federated accounts were kind of lost in the void instead)
-
Guestbook support (optional): mentions to the federated Madblog handle that are not in response to articles are now rendered on a separate
/guestbookroute -
Email notifications: all interactions can have email notifications
-
Support for quotes, also on Mastodon
-
Support for mentions, just drop a
@joe@example.comin your Markdown file and Joe will get a notification -
Support for hashtag federation
-
Support for split-domain configurations, you can host your blog on
blog.example.combut have a Fediverse handle like@blog@example.com. Search by direct post URL on Mastodon will work with both cases -
Support for custom profile fields, all rendered on Mastodon, with verification support
-
Support for moderation, either through blocklist or allowlist, with support for rules on handles/usernames, URLs, domains or regular expressions
-
A partial (but comprehensive for the provided features) implementation of the Mastodon API
If you want you can follow both the profiles of my blogs - they are now both federated:
-
My personal blog: @fabio@manganiello.blog (it used to run WriteFreely before, so if you followed it you may need to unfollow it and re-follow it)
-
The #Platypush blog: @blog@platypush.tech
@fabio@manganiello.eu @fabio@manganiello.blog @blog This looks really cool. Iβve always been kinda interested in federating my blog, or having my fedi account be more closely associated with my main blog domain. This looks like a path to doing something in that realm. Out of curiosity, would it be possible to stand something like this up and migrate followers from an existing fedi account to it? Thanks!
-
-
cc @gabboman not able to follow or look up these new actors in WAFRN
@wakest@app.wafrn.net @gabboman@gabboman.xyz @liaizon@wake.st the FQN is
@fabio@manganiello.blogin my case, not@fabio@blog.fabiomanganiello.com(I made a split-domain configuration).The actor URL is
https://manganiello.blog/ap/actor -
@wakest@app.wafrn.net @gabboman@gabboman.xyz @liaizon@wake.st the FQN is
@fabio@manganiello.blogin my case, not@fabio@blog.fabiomanganiello.com(I made a split-domain configuration).The actor URL is
https://manganiello.blog/ap/actorwill investigate, thanks
-
@liaizon @fabio Alas, the PR has been merged, so it'll be a long while until I bother Claire again.

But I'll keep updating my own list. I see in the code where the interaction policy is declared, but not where individual quotes are authorized. If I quote this post here, let's test if both of us will see the quote.
@julian@fietkau.social @liaizon@wake.st I got the quote https://blog.fabiomanganiello.com/article/Madblog-federated-blogging-from-markdown

-
@julian@fietkau.social @liaizon@wake.st I got the quote https://blog.fabiomanganiello.com/article/Madblog-federated-blogging-from-markdown

@fabio Right, and my server seems to have gotten the corresponding `Accept`.
But if you look at https://social.wake.st/@liaizon/116205306320048221 and scroll down, you see that @liaizon can't see the quote in my reply (and neither can people on any other server looking at this thread). This is because the `QuoteAuthorization` needs to be publicly resolvable: https://fediverse.codeberg.page/fep/fep/044f/#verifying-third-party-quote-posts -
@fabio Right, and my server seems to have gotten the corresponding `Accept`.
But if you look at https://social.wake.st/@liaizon/116205306320048221 and scroll down, you see that @liaizon can't see the quote in my reply (and neither can people on any other server looking at this thread). This is because the `QuoteAuthorization` needs to be publicly resolvable: https://fediverse.codeberg.page/fep/fep/044f/#verifying-third-party-quote-posts@julian@fietkau.social @liaizon@wake.st good catch, that was actually a bug in the
quote_authorizationsURL routing on Pubby's side - I've just pushed a fix for it https://git.platypush.tech/blacklight/pubby/commit/2b37e604defb8dbd9580af890c5854c2f9cd9dfd -
@julian@fietkau.social @liaizon@wake.st good catch, that was actually a bug in the
quote_authorizationsURL routing on Pubby's side - I've just pushed a fix for it https://git.platypush.tech/blacklight/pubby/commit/2b37e604defb8dbd9580af890c5854c2f9cd9dfd -
@julian@activitypub.space @general@activitypub.space that would be very cool, but from my understanding Person vs. Group actor are mutually exclusive, so I can't have both on the same handle right?
If that's the case I may have to rethink a bit of the current single-user approach - I guess that I'll need a
@user@example.comPerson actor (or optionally multiple of them) and a@blog@example.comGroup actor. Which AFAIK is similar to what #WriteFreely does, but it requires me to rethink a bit of the general design.I've braindumped my thoughts here for now https://git.platypush.tech/blacklight/madblog/issues/21, thanks for the feedback!
-
R relay@relay.mycrowd.ca shared this topic
-
@julian@activitypub.space @general@activitypub.space that would be very cool, but from my understanding Person vs. Group actor are mutually exclusive, so I can't have both on the same handle right?
If that's the case I may have to rethink a bit of the current single-user approach - I guess that I'll need a
@user@example.comPerson actor (or optionally multiple of them) and a@blog@example.comGroup actor. Which AFAIK is similar to what #WriteFreely does, but it requires me to rethink a bit of the general design.I've braindumped my thoughts here for now https://git.platypush.tech/blacklight/madblog/issues/21, thanks for the feedback!
> from my understanding Person vs. Group actor are mutually exclusive, so I can't have both on the same handle right?
Correct, while you can have webfinger resolve both a group actor and person actor from a single handle, that gets messy quickly because how the receiving end handles this is not specified. Mastodon for example only takes the first entry, which crucially means if a community and user have the same handle, then one of the actors is inaccessible to Mastodon.
Here are some quick answers to the open questions:
Should the Person actor have its own inbox?
Yes, the Person actor and the Group actor are two separate identities (as far as anybody outside of your instance is concerned.Outbox representation β Should the Group's outbox contain the Announce
activities, the inner Create activities, or both?This is optional (at least for NodeBB). If you investigate NodeBB's actors, all of their outboxes return an empty OrderedCollection because I simply haven't gotten around to it yet, and I don't know many implementations that read it. Federation works fine without it, but it would make sense to follow Lemmy or Piefed's lead here.
Backwards compatibility β Should Madblog support a "hybrid" mode that sends both Create (for Mastodon) and Announce (for threadiverse)?
Mastodon will correctly de-duplicate the object so sending both
Create(Note/Article)andAnnounce(Create(Note/Article))is fine. The former serves non-threadiverse followers, and the latter ensures threadiverse syncronization capability.Separate keypair for the Person actor? If the Person actor eventually needs to sign requests (e.g. for inbox delivery), it would need its own keypair.
I believe so. It was trivial for me to just generate keypairs for everybody, so I don't know off-hand whether things break if your Person actor doesn't have one. It might not resolve in some implementations?
-
N nodebb@fosstodon.org shared this topic
-
@silverpill@mitra.social @fabio@manganiello.blog good catch! https://git.platypush.tech/blacklight/madblog/commit/9024ba9c2dd1b4ad77e50892189c6a155eb199ce
@fabio @fabio Will it also work with
profileparameter? We have to specify the profile because ActivityPub specification requires it:ActivityPub
The ActivityPub protocol is a decentralized social networking protocol based upon the [ActivityStreams] 2.0 data format. It provides a client to server API for creating, updating and deleting content, as well as a federated server to server API for delivering notifications and content.
(www.w3.org)
-
If you investigate NodeBB's actors, all of their outboxes return an empty OrderedCollection because I simply haven't gotten around to it yet, and I don't know many implementations that read it.
I read from outboxes all the time. But I can't do that with NodeBB

Outbox doesn't have an `id` Β· Issue #13478 Β· NodeBB/NodeBB
NodeBB version v4.4.2 NodeBB git hash No response NodeJS version No response Installed NodeBB plugins No response Database type No response Database version No response Exact steps to cause this issue Retrieve outbox What you expected I ...
GitHub (github.com)
-
@silverpill@mitra.social @fabio@manganiello.blog yes, I've just realized that luckily
requestsis smart enough to split header parameters
β― curl -I -H 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams' https://manganiello.blog/article/Madblog-federated-blogging-from-markdown HTTP/2 200 server: nginx date: Tue, 10 Mar 2026 18:43:44 GMT content-type: application/activity+json content-length: 69389 last-modified: Tue, 10 Mar 2026 18:39:54 GMT etag: "81d02d339405c0ec" cache-control: public, max-age=0, must-revalidate language: en-US -
@silverpill@mitra.social @fabio@manganiello.blog you're right, I completely overlooked that. Also the Python HTTP machinery isn't as clever as I thought so I had to trim parameters manually, but it should work now https://git.fabiomanganiello.com/blacklight/madblog/commit/76e7b72337b1ab7406fb307eb163a9a4097fcc0e
β― curl -I -H 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"' https://manganiello.blog/article/Madblog-federated-blogging-from-markdown HTTP/2 200 server: nginx date: Tue, 10 Mar 2026 19:06:01 GMT content-type: application/activity+json content-length: 69389 last-modified: Tue, 10 Mar 2026 18:39:54 GMT etag: "81d02d339405c0ec" cache-control: public, max-age=0, must-revalidate language: en-US -
If you investigate NodeBB's actors, all of their outboxes return an empty OrderedCollection because I simply haven't gotten around to it yet, and I don't know many implementations that read it.
I read from outboxes all the time. But I can't do that with NodeBB

Outbox doesn't have an `id` Β· Issue #13478 Β· NodeBB/NodeBB
NodeBB version v4.4.2 NodeBB git hash No response NodeJS version No response Installed NodeBB plugins No response Database type No response Database version No response Exact steps to cause this issue Retrieve outbox What you expected I ...
GitHub (github.com)
@silverpill@mitra.social I recall Mitra may be one of a select few

Do you use it to backfill a profile? How often do you query the outbox?
-
@silverpill@mitra.social @fabio@manganiello.blog you're right, I completely overlooked that. Also the Python HTTP machinery isn't as clever as I thought so I had to trim parameters manually, but it should work now https://git.fabiomanganiello.com/blacklight/madblog/commit/76e7b72337b1ab7406fb307eb163a9a4097fcc0e
β― curl -I -H 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"' https://manganiello.blog/article/Madblog-federated-blogging-from-markdown HTTP/2 200 server: nginx date: Tue, 10 Mar 2026 19:06:01 GMT content-type: application/activity+json content-length: 69389 last-modified: Tue, 10 Mar 2026 18:39:54 GMT etag: "81d02d339405c0ec" cache-control: public, max-age=0, must-revalidate language: en-US -
@silverpill@mitra.social I recall Mitra may be one of a select few

Do you use it to backfill a profile? How often do you query the outbox?
-
@julian Yes, to backfill a profile. It is a manual action.
I don't know who else does that, but @jonny is working on adding automatic profile backfill to Mastodon: https://github.com/mastodon/mastodon/pull/34597
@silverpill @julian@activitypub.space I believe @hollo does it as well.
-
#ActivityPub support in #Madblog
I am glad to announce that Madblog has now officially joined the #Fediverse family.
Madblog has already supported #Webmentions for the past couple of weeks, allowing your blog posts to be mentioned by other sites with Webmentions support (WordPress, Lemmy, HackerNews...) and get those mentions directly rendered on your page.
It now adds ActivityPub support too, using #Pubby, another little Python library that I've put together myself (just like Webmentions) as a mean to quickly plug ActivityPub support to any Python Web app.
Webmentions and Pubby follow similar principles and implement a similar API, and you can easily use them to add federation support to your existing Web applications - a single
bind_webmentionsorbind_activitypubcall to your existing Flask/FastAPI/Tornado application should suffice for most of the cases.Madblog may have now become the easiest way to publish a federated blog - and perhaps the only way that doesn't require a database, everything is based on plain Markdown files.
If you have a registered domain and a certificate, then hosting your federated blog is now just a matter of:
mkdir -p ~/madblog/markdown cat <<EOF > ~/madblog/markdown/hello-world.md This is my first post on [Madblog](https://git.fabiomanganiello.com/madblog)! EOF docker run -it \ -p 8000:8000 \ -v "$HOME/madblog:/data" \ quay.io/blacklight/madblogAnd Markdown files can be hosted wherever you like - a Git folder, an Obsidian Vault, a Nextcloud Notes installation, a folder on your phone synchronized over SyncThing...
Federation support is also at a quite advanced state compared to e.g. #WriteFreely. It currently supports:
-
Interactions rendered on the articles: if you like, boost, quote or reply to an article, all interactions are rendered directly at the bottom of the article (interactions with WriteFreely through federated accounts were kind of lost in the void instead)
-
Guestbook support (optional): mentions to the federated Madblog handle that are not in response to articles are now rendered on a separate
/guestbookroute -
Email notifications: all interactions can have email notifications
-
Support for quotes, also on Mastodon
-
Support for mentions, just drop a
@joe@example.comin your Markdown file and Joe will get a notification -
Support for hashtag federation
-
Support for split-domain configurations, you can host your blog on
blog.example.combut have a Fediverse handle like@blog@example.com. Search by direct post URL on Mastodon will work with both cases -
Support for custom profile fields, all rendered on Mastodon, with verification support
-
Support for moderation, either through blocklist or allowlist, with support for rules on handles/usernames, URLs, domains or regular expressions
-
A partial (but comprehensive for the provided features) implementation of the Mastodon API
If you want you can follow both the profiles of my blogs - they are now both federated:
-
My personal blog: @fabio@manganiello.blog (it used to run WriteFreely before, so if you followed it you may need to unfollow it and re-follow it)
-
The #Platypush blog: @blog@platypush.tech
@fabio I really, really love it!! I wanted to do the same for quite a long time - but I didn't; and now maybe I can eventually steal your code and RIIR in glorious AGPL!
That said, unfortunately at the moment it's not working for me, I can't open it either in my client, or through my instance's search
FWIW, through my instance I'm seeing some "503 Remote SSL certificate could not be verified", while the client just spins a throbber endlessly. No idea where the fault lies, but I do remember reading many times that Mastodon is a flustercluck and a fishy citizen in ActivityPub
...Anyway, huge applause from me regardless, and hopefully one day I can get to fave the actual post on the blog!
-