home.social

#madblog — Public Fediverse posts

Live and recent posts from across the Fediverse tagged #madblog, aggregated by home.social.

fetched live
  1. 🇬🇧 Thank you to @devconf for giving me the unique chance to speak about #Madblog, #ActivityPub, #Indieweb and federated blogging in front of an Italian audience.

    Thanks to all the amazing speakers who brought their own experiences and perspectives on topics such as open-source, IT governance, democratization of software and building European alternatives.

    Thanks to the organizers who made sure that the event was a success, and to the university of Pavia for hosting us.

    Full content of the conference:

    See you next time!

    🇮🇹 Grazie a #DevConf per avermi concesso l’opportunità unica di parlare di Madblog, ActivityPub, Indieweb e blogging federato di fronte a un pubblico italiano.

    Grazie a tutti i meravigliosi relatori che hanno portato le loro preziose esperienze e prospettive su temi quali open-source, IT governance, democratizzazione del software e sviluppo di alternative europee.

    Grazie a tutti gli organizzatori che hanno reso quest’evento un successo, e all’università di Pavia per averci ospitato.

    Contenuti completi della conferenza:

    Alla prossima!

  2. #DevConf is just a week away.

    I will be speaking about #Madblog, #ActivityPub and #Indieweb on July 8th, from 11:30 AM to 12:15 PM.

    Location: Biblioteca Cravino, Via Agostino Bassi 2, Pavia, Italy.

    If you can’t attend in person but still want to see the presentation (bear in mind that it’ll be in Italian though), the live stream will be published here https://www.youtube.com/@BoostMediaAPS/streams

    @devconf

    RE: https://mastodon.uno/@BoostMediaAPS/116838612189127953

  3. I will be speaking about #Madblog and self-built ActivityPub blogging solutions in Pavia, Italy, on July 8th, accompained by many other amazing friends from the Fediverse and beyond.

    Thank you @devconf for giving me this great opportunity!

  4. @[email protected]

    Is there a complete documentation of all configuration variables? In the config yaml example I didn't find the nav_links variable.

    It's in the example - but I've added it today, the timing was perfect because I also needed it to migrate my personal website.

    A full reference of the configuration parameters is on the README too.

    if I want to link to a specific blog's article?

    If you link to a blog article from another blog article a Webmention will be automatically sent out, so you can see the comment under the original page.

    If you or anyone replies to a post from Mastodon and enable_activitypub is true then the reply will also be rendered automatically under the original page.

    If you instead you mean "adding a link to another article in the nav bar", that should be possible always with nav_links:

    nav_links:
      - name: Some Important Post
        url: /article/some-important-post
        icon: https://madblog.plusbrothers.net/img/myicon.png
    

    If I want to place the guestbook page into the nav bar, should I link the whole http URL or just /guestbook?

    Both should work. But you don't need to explicitly add the guestbook to the nav bar - it's automatically added if either Webmentions or ActivityPub are enabled and enable_guestbook is not set to false.

    Then - on WriteFreely, if I publish a post and pin it, it goes to header's links.

    Proper support for pinned collections hasn't yet been implemented (it requires implementing ActivityPub collections on Pubby too).

    The workaround for now is simply to add links to nav_links.

    But every markdown post I upload on madblog, gets into the Rss I think, like normal posts, even if it's not a post but a "static" page

    Everything #markdown file you put under markdown on #madblog is also included in the RSS feed - unless you set default_visibility to non-public in the configuration or set e.g. [//]: # (visibility: unlisted) (or followers, direct or draft) in the Markdown headers.

  5. Support for About Me and custom nav links

    @[email protected] @[email protected] I've had a bit of time today to put together a new #madblog version 🙂

    About Me

    Now you can just drop an ABOUT.md in your pages directory. If you provide the right metadata in the #markdown header you also get a nicely rendered semantic h-card as a bonus.

    An example from the header of my site's about page (trim the initial spaces, otherwise Madblog interprets these as true headers and messes up this post):

     [//]: # (title: My Name)
     [//]: # (name: My Name)
     [//]: # (given-name: My)
     [//]: # (family-name: Name)
     [//]: # (url: https://example.com)
     [//]: # (photo: https://example.com/photo.jpg)
     [//]: # (email: [email protected])
     [//]: # (job-title: Cat herder)
     [//]: # (org: My Company|https://example.com, My Side Project|https://another-example.com)
     [//]: # (note: Some brief description)
     [//]: # (key: https://pgp.example.com/key.txt|FINGERPRINT)
     [//]: # (links: @[email protected]|https://example.social/@me, Github|https://github.com/me, LinkedIn|https://www.linkedin.com/in/me/, XMPP|xmpp://[email protected], Matrix|https://matrix.to/#/@me:example.com)
    

    External Links

    You can add them now to your config.yaml.

    # rel_me links are only for verification /
    # Mastodon-double linking purposes, but
    # they are not rendered on the HTML
    rel_me:
      - https://example.social/@me
      - https://goto.social/@name
    
    # External links are automatically rendered
    # on the about page
    external_links:
      - url: https://example.social/@me
        display_name: Mastodon
    
    # nav_links are automatically rendered
    # on the navigation panel
    nav_links:
      - url: https://example.social/@me
        display_name: Mastodon
        icon: https://example.social/favicon.ico
    
  6. @elettrona maybe this article can help.

    If you need a docker-compose for #Madblog it should be relatively straightforward.

    Then, quoting the original article:

    Install the Reverse Proxy app YunoHost app store | Reverse Proxy, choose the domain and then in the field Redirect destination path (unix:/file for socket) add the port, in this case 127.0.0.1:8000

  7. New post: The Markdown Link no. 10

    Among today’s links are code editor Voiden, minimal blog framework Madblog, and markdown editors uFocus, Notebooks, Inkdrop and Dumbnote.

    md-handbook.com/blog/markdown-

    #markdown #markdowneditors #codeeditors #Voiden #Madblog #uFocus #Notebooks #Inkdrop #Dumbnote

  8. @weekinfediverse there have been a bunch of updates to @fabio's #MadBlog this week too

  9. https://blog.fabiomanganiello.com/reply/unlisted-posts

    The latest version of #madblog introduces a separate page, under /unlisted, for posts that the author can send to the Fediverse (or simply keep in a separate area of their blog) without publishing them on the index.

    This is useful for quick thoughts and interactions. Worth enough to mention, but not enough to deserve their own dedicate article on the blog frontpage.

    To create an unlisted post, simply create a Markdown file under /replies/ with no like-of and reply-to metadata headers:

    cd $MADBLOG_DATADIR
    mkdir -p replies
    
    cat <<EOF > replies/unlisted-post.md
    # My first unlisted post
    
    I thought that it'd be cool to share with my followers on Mastodon that now I can trace likes and replies with git bisect.
    
    I'll also tag @[email protected] because he'll probably think it's cool.
    

    Save the file, then you will find your post on the /unlisted page.

  10. @ricmac #Madblog has native support for #Webmentions, and unlike #ActivityPub they’re enabled by default.

    I’ve tried to make it as simple as possible and avoid manual callbacks or special tags for mentioned links.

    You put a link in an article, and when you save it Webmentions are sent to supported targets. Someone mentions your article from a place that supports Webmentions, and the mention is stored on your blog.

  11. Federated Replies and Reactions in Madblog

    Engage with the Web from plain text files

    Madblog is founded on a simple principle: a blog is just a collection of #markdown files in a folder. No databases, no logins, no client-side bloat — just files.

    The recently implemented support for both Webmentions and ActivityPub add an extra appeal to this approach: now those text files can federate, they can send mentions to Wordpress blogs or Mastodon accounts, and you can visualize mentions, comments and reactions from other corners of the Web directly under your articles.

    But after receiving in the past few days a bunch of reactions on my blog that I couldn't interact with, which forced me to fall back on my standard Fediverse account to send replies and likes, I've decided to take the "everything is a file" philosophy a step further.

    Now from #madblog you can also reply to comments and react to posts across the Fediverse - all from plain text files in your content folder.

    Replying to Comments

    When someone comments on your article from Mastodon or another ActivityPub-compatible services, their message appears on your blog.

    Now you can also respond directly from your blog.

    Or you can reply to any other post on the Fediverse or mention anyone, without those posts cluttering your blog's front page (I've learned to avoid this fatal design mistake made by e.g. Medium).

    How it works

    Create a Markdown file under replies/<article-slug>/:

     [//]: # (reply-to: https://mastodon.social/@alice/123456789)
    
    Thanks for the kind words, Alice! I'm glad the tutorial helped.
    
    @alice@mastodon.social
    

    Save the file, and Madblog automatically:

    • Publishes your reply to the Fediverse as a threaded response
    • Notifies Alice on her Mastodon instance
    • Displays the reply on your blog, nested under her original comment

    Your reply lives in your content folder. Just like with your articles, you can version replies and reactions on git, synchronize them over SyncThing or Nextcloud Notes, or run some analysis scripts on them that would just operate on text files.

    Replying to replies

    Conversations can go as deep as you want. Reply to a reply by pointing reply-to at the previous message's URL:

     [//]: # (reply-to: https://mastodon.social/@alice/123456790)
    
    Great question! I'll write a follow-up post about that.
    
    @alice@mastodon.social
    

    The threading is preserved both on your blog and across the Fediverse.

    [Example of a nested thread rendered on Madblog]

    (I hope that @[email protected] and @[email protected] won't mind for using a screenshot from their conversation on my blog 🙂)

    Remember to mention your mentions

    An important implementation note: if you're replying to someone else's ActivityPub post, it's important that you also mention them in the reply, otherwise your reply will be rendered under their comment but they may not be notified.

    Usually you don't have to worry about this on Mastodon because the UI will automatically pre-fill the participating accounts in a sub-thread when you hit Reply.

    But this is something to keep in mind when your posts are just text files.

    Your replies are articles in their own right

    Even though anything under replies/ won't appear on your blog's home page, it doesn't mean that it must be rendered just like a humble rectangle in a crowded comments section.

    By clicking View full reply you get redirected to a separate page where the reply is rendered as a blog article, and its comments sections consists in the sub-tree of the reactions that spawned from that specific reply.

    [Example of a Madblog reply rendered as a blog article, with its own sub-thread of reactions]

    Liking Posts

    Sometimes a reply is too much — you just want to show appreciation. Now you can "like" any post on the Fediverse with a simple metadata header.

    Standalone likes

    Create a file under replies/ with just a like-of header:

     [//]: # (like-of: https://mastodon.social/@bob/987654321)
    

    This publishes a Like activity to the Fediverse. Bob sees the notification, and your blog records the interaction.

    Like and comment

    Want to like and say something? Combine both:

     [//]: # (like-of: https://mastodon.social/@bob/987654321)
     [//]: # (reply-to: https://mastodon.social/@bob/987654321)
    
    This is such a great point! Bookmarking for later.
    
    @bob@mastodon.social
    

    Bob gets both the like and your reply as a threaded response.

    Unlisted Posts

    Not everything needs to appear on your blog's front page. Files under replies/ without reply-to and like-of headers become "unlisted" posts — they're published to the Fediverse but don't clutter your blog index.

    Perfect for quick thoughts, threads, or conversations that don't warrant a full article.

     [//]: # (title: Thoughts of the day)
    
    Quick thought: I've been experimenting with writing all my Fediverse posts
    as Markdown files. It's oddly satisfying to `git log` my social media history.
    

    Guestbook Replies

    Your blog's guestbook works the same way. Reply to guestbook entries by placing files under replies/_guestbook/:

     [//]: # (reply-to: https://someone.blog/mention/123)
    
    @alice@example.com welcome! Thanks for stopping by.
    

    Editing and Deleting

    Changed your mind? Edit the file and an Update activity is sent. Delete the file and your reply is removed from the Fediverse too.

    Accidentally liked something? Remove the like-of line (or delete the file) and an Undo Like is published.

    Your content, your rules.

    Getting Started

    1. Enable ActivityPub in your config.yaml:
    link: https://blog.example.com
    enable_activitypub: true
    activitypub_username: blog
    
    # Only specify these if you want your ActivityPub domain to be different from your blog domain
    # activitypub_link: https://example.com
    # activitypub_domain: example.com
    
    1. Install Madblog
    • From pip:
    pip install madblog
    
    • From Docker:
    docker pull quay.io/blacklight/madblog
    
    1. Run Madblog from your Markdown folder (it is recommended that your articles are stored under <data-dir>/markdown):
    • From a pip installation:
    madblog /path/to/data
    
    • From Docker:
    docker run -it \
      -p 8000:8000 \
      -v "/path/to/config.yaml:/etc/madblog/config.yaml" \
      -v "/path/to/data:/data" \
      quay.io/blacklight/madblog
    
    1. Any text file you create under markdown/ becomes a blog article. Any text file you create under replies/ becomes an unlisted post, a reply or a like reaction.

    Check the README for detailed configuration options.

    Happy blogging!

  12. Fabio Manganiello (@fabio)
    @[email protected]
    poliverso.org/display/96e44936

    Madblog è entrato ufficialmente a far parte della famiglia del #Fediverso!#Madblog è una piattaforma di blogging semplice da gestire tramite file Markdown.Nessuna interfaccia complessa. Nessun JavaScript. Nessun dB o script di migrazione. Nessun plugin non sicuro. Solo una cartella git, un vault Obsidian o una directory SyncThing sincronizzata, e la possibilità di

  13. informapirata ⁂ :privacypride:: "Madblog è entrato ufficialment…" - Mastodon Uno Social - Italia

    mastodon.uno/@informapirata/11

    > Madblog è entrato ufficialmente a far parte della famiglia del #Fediverso! #Madblog è una piattaforma di blogging semplice da gestire tramite file Markdown. Nessuna interfaccia complessa. Nessun JavaScript. Nessun dB o script di migrazione. Nessun plugin non sicuro. Solo una cartella git, un vault Obsidian @fabio @fediverso

  14. o una directory SyncThing sincronizzata, e la possibilità di creare e modificare contenuti semplicemente scrivendo file di testo! Il post di @fabio manganiello.eu/notice/B47BLSKr @fediverso
    @informapirata

    #Fediverso #Madblog

  15. Madblog è entrato ufficialmente a far parte della famiglia del #Fediverso!

    #Madblog è una piattaforma di blogging semplice da gestire tramite file Markdown.
    Nessuna interfaccia complessa. Nessun JavaScript. Nessun dB o script di migrazione. Nessun plugin non sicuro. Solo una cartella git, un vault Obsidian o una directory SyncThing sincronizzata, e la possibilità di creare e modificare contenuti semplicemente scrivendo file di testo!

    Il post di @fabio

    manganiello.eu/notice/B47BLSKr

    @fediverso

  16. #ActivityPub support in #Madblog

    https://blog.fabiomanganiello.com/article/Madblog-federated-blogging-from-markdown

    I am glad to announce that Madblog has now officially joined the #Fediverse family.

    If you want to test it out, search for this URL on your Fediverse client.

    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_webmentions or bind_activitypub call 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
    # My first post
    
    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/madblog

    And 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 /guestbook route

    • Email notifications: all interactions can have email notifications

    • Support for quotes, also on Mastodon

    • Support for mentions, just drop a @[email protected] in 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.com but have a Fediverse handle like @[email protected]. 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 (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

  17. Madblog: A Markdown Folder That Federates Everywhere

    A lightweight blogging engine based on text files, with native Fediverse and IndieWeb support

    I started working on Madblog a few years ago.

    I wanted a simple blogging platform that I could run from my own Markdown files. No intermediaries. No bloated UI. No JavaScript. No databases and migration scripts. No insecure plugins. Just a git folder, an Obsidian vault or a synchronized SyncThing directory, and the ability to create and modify content by simply writing text files, wherever I am.

    Drop a Markdown file in the directory, and it's live. Edit it, and the changes propagate. Delete it, and it's gone.

    It's been running my personal blog and the Platypush blog for a while now.

    With the new release, #madblog now gets a new superpower: it supports federation, interactions and comments both through:

    Webmentions allow your site to mention and be mentioned by other sites that also implement them - like any WordPress blog with the Webmention plugin, or link aggregators like Lemmy or HackerNews. Interactions with any of your pages will be visible under them.

    #activitypub support allows Madblog to fully federate with Mastodon, Pleroma, Misskey, Friendica or any other #fediverse instance. It turns your blog into a federated handle that can be followed by anyone on the Fediverse. It gives you the ability to mention people on the Fediverse directly from your text files, and get replies to your articles directly from Mastodon, get your articles boosted, shared and quoted like any other Mastodon post.

    Demos

    These blogs are powered by Madblog:

    You can follow them from Mastodon (or any other Fediverse client), reply to articles directly from your instance, boost them, or quote them. You can also interact via Webmentions: link to an article from your own site, and if your site supports Webmentions, the mention will show up as a response on the original post. These blogs also have a Guestbook — mention the blog's Fediverse handle or send a Webmention to the home page, and your message appears on a public guest registry.

    How Does It Compare?

    If you've looked into federated blogging before, you've likely come across a few options:

    • WriteFreely is probably the closest alternative — a minimalist, Go-based platform with ActivityPub support. It's well-designed, but it uses a database (SQLite or MySQL), has its own (very minimal) editor, and doesn't support Webmentions. Additionally, it lacks many features that are deal-breakers for me.
    • No export of all the content to Markdown, nor ability to run my blog from my Nextcloud Notes folder or Obsidian vault.
    • No support for LaTeX or Mermaid diagrams.
    • No support for federated interactions - any interaction with your articles on the Fediverse is simply lost.
    • The UI is minimalist and not necessarily bad, but not even sufficiently curated for something like a blog (narrow width, Serif fonts not optimized for legibility, the settings and admin panels are a mess...).
    • No support for moderation / content blocking.
    • No support for federated hashtags.

    • WordPress with ActivityPub and Webmention plugins can technically do what Madblog does, but it's a full CMS with a database, a theme engine, a plugin ecosystem, and a much larger attack surface. If all you need is a blog, it's overkill.

    • Plume and Friendica offer blogging with federation, but they're full social platforms, not lightweight publishing tools.

    Madblog sits in a different niche: it's closer to a static-site generator that happens to speak federation protocols. It implements a workflow like "write Markdown, push to server, syndicate everywhere".

    Getting Started

    Docker Quickstart

    mkdir -p ~/madblog/markdown
    cat <<EOF > ~/madblog/markdown/hello-world.md
    # Hello, Fediverse!
    
    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/madblog
    

    Open http://localhost:8000. That's it — you have a blog.

    The default Docker image (quay.io/blacklight/madblog) is a minimal build (< 100 MB) that includes everything except LaTeX and Mermaid rendering. If you need those, build the full image from source:

    git clone https://git.fabiomanganiello.com/madblog
    cd madblog
    docker build -f docker/full.Dockerfile -t madblog .
    

    See the full Docker documentation for details on mounting config files and ActivityPub keys.

    Markdown structure

    Since there's no database or extra state files involved, the metadata of your articles is also stored in Markdown.

    Some things (like title, description) can be inferred from the file name, headers of your files etc., creation date defaults to the creation timestamp of the file and author and language are inherited from your config.yaml.

    A full customized header would look like this:

     [//]: # (title: Title of the article)
     [//]: # (description: Short description of the content)
     [//]: # (image: /img/some-header-image.png)
     [//]: # (author: Author Name <https://author.me>)
     [//]: # (author_photo: https://author.me/avatar.png)
     [//]: # (language: en-US)
     [//]: # (published: 2022-01-01)
    
    ...your Markdown content...
    

    Key Configuration

    Madblog reads configuration from a config.yaml in your content directory. Every option is also available as an environment variable with a MADBLOG_ prefix — handy for Docker or CI setups.

    A minimal config to get started:

    title: My Blog
    description: Thoughts on tech and life
    link: https://myblog.example.com
    author: Your Name
    

    Or purely via environment variables:

    docker run -it \
      -p 8000:8000 \
      -e MADBLOG_TITLE="My Blog" \
      -e MADBLOG_LINK="https://myblog.example.com" \
      -e MADBLOG_AUTHOR="Your Name" \
      -v "$HOME/madblog:/data" \
      quay.io/blacklight/madblog
    

    See config.example.yaml for the full reference.

    It is advised to keep all of your Markdown content under <data-dir>/markdown, especially if you enable federation, in order to keep the Markdown folder tidy from all the auxiliary files generated by Madblog.

    Webmentions

    Webmentions are the IndieWeb's answer to trackbacks and pingbacks — a W3C standard that lets websites notify each other when they link to one another. Madblog supports them natively, both inbound and outbound.

    When someone links to one of your articles from a Webmention-capable site, your blog receives a notification and renders the mention as a response on the article page. Going the other way, when you link to an external URL in your Markdown and save the file, Madblog automatically discovers the target's Webmention endpoint and sends a notification — no manual step required. All mentions are stored as Markdown files under your content directory (mentions/incoming/<post-slug>/), so they're version-controllable and easy to inspect.

    You can enable pending-mode for moderation (webmentions_default_status: pending), or use the blocklist/allowlist system to filter sources by domain, URL, or regex. Webmentions are enabled by default — if you're running Madblog locally for testing, set enable_webmentions: false to avoid sending real notifications to external sites.

    ActivityPub Federation

    ActivityPub is the protocol that powers the Fediverse — Mastodon, Pleroma, Misskey, and hundreds of other platforms. Madblog implements it as a first-class feature: enable it, and your blog becomes a Fediverse actor that people can follow, reply to, boost, and quote.

    Enable it in your config:

    enable_activitypub: true
    activitypub_username: blog
    activitypub_private_key_path: /path/to/private_key.pem
    

    Madblog will generate an RSA keypair on first start if you don't provide one. Once enabled, your blog gets a Fediverse handle (@[email protected]), a WebFinger endpoint for discovery, and a full ActivityPub actor profile. New and updated articles are automatically delivered to all followers' timelines.

    Here's what federation looks like in practice:

    • Receiving mentions: when someone mentions your blog's Fediverse handle in a public post (not as a reply to a specific article), the mention shows up on your Guestbook page.
    • Receiving replies, likes, boosts, and quotes: interactions targeting a specific article are rendered below that article — replies as threaded comments, likes/boosts/quotes as counters and cards. All stored as JSON files on disk.
    • Sending mentions: just write the fully-qualified handle in your Markdown (@[email protected]) and save the file. Madblog resolves the actor via WebFinger and delivers a proper ActivityPub Mention tag — the mentioned user gets a notification on their instance.
    • Federated hashtags: hashtags in your articles (#Python, #Fediverse) are included as ActivityPub Hashtag tags in the published object. Followers who track those hashtags on their instance will see your posts in their filtered feeds.
    • Custom profile fields: configure additional profile metadata (verified links, donation pages, git repos) that show up on your actor's profile as seen from Mastodon and other Fediverse clients:

    yaml activitypub_profile_fields: Git repository: <https://git.example.com/myblog> Donate: <https://liberapay.com/myprofile>

    The federation layer also exposes a read-only subset of the Mastodon API, so Mastodon-compatible clients and crawlers can discover the instance, look up the actor, list published statuses, and search for content — with no extra configuration.

    Madblog also supports advanced ActivityPub features like split-domain setups (e.g. your blog at blog.example.com but your Fediverse handle at @[email protected]), configurable object types (Note for inline rendering on Mastodon vs. Article for link-card previews), and quote policies (FEP-044f, so Mastodon users can quote your articles too).

    LaTeX and Mermaid

    Madblog supports server-side rendering of LaTeX equations and Mermaid diagrams directly in your Markdown files — no client-side JavaScript required.

    LaTeX uses latex + dvipng under the hood. Inline expressions use conventional LaTeX markers:

    The Pythagorean theorem states that \(c^2 = a^2 + b^2\).
    
    $$
    E = mc^2
    $$
    

    Mermaid diagrams use standard fenced code blocks. Both light and dark theme variants are rendered at build time and switch automatically based on the reader's color scheme:

     ```mermaid
     graph LR
         A[Write Markdown] --> B[Madblog renders it]
         B --> C[Fediverse sees it]
     ```
    

    Install Mermaid support with pip install "madblog[mermaid]" or use the full Docker image. Rendered output is cached, so only the first render of each block is slow.

    Tags and Categories

    Tag your articles with hashtags — either in the metadata header or directly in the body text:

    # My Article
    
    This post is about #Python and the #Fediverse.
    

    Madblog builds a tag index at /tags, with per-tag pages at /tags/<tag>. Hashtags from incoming Webmentions are also indexed. Folders in your content directory act as categories — if you organize files into subdirectories, the home page groups articles by folder.

    Feed Syndication

    Madblog generates both RSS and Atom feeds at /feed.rss and /feed.atom. You can control whether feeds include full article content or just descriptions (short_feed: true), and limit the number of entries (max_entries_per_feed: 10). limit and offset parameters are also supported for pagination.

    Aggregator Mode

    Madblog can also pull in external RSS/Atom feeds and render them alongside your own posts on the home page — useful for affiliated blogs, or even as a self-hosted feed reader:

    external_feeds:
      - https://friendsblog.example.com/feed.atom
      - https://colleaguesblog.example.com/feed.atom
    

    Guestbook

    The guestbook (/guestbook) is a dedicated page that aggregates public interactions — Webmentions targeting the home page and Fediverse mentions of your blog actor that aren't replies to specific articles. Think of it as a public guest registry, or a lo-fi comment section for your blog as a whole. Visitors can leave a message by mentioning your Fediverse handle or sending a Webmention. It can be disabled via enable_guestbook=0.

    View Modes

    The home page supports three layouts:

    • cards (default) — a responsive grid of article cards with images
    • list — a compact list with titles and dates
    • full — a scrollable, WordPress-like view with full article content inline

    Set it in your config (view_mode: cards) or override at runtime with ?view=list.

    Moderation

    Madblog ships with a flexible moderation system that applies to both Webmentions and ActivityPub interactions. You can run in blocklist mode (reject specific actors) or allowlist mode (accept only specific actors), with pattern matching by domain, URL, ActivityPub handle, or regex:

    blocked_actors:
      - spammer.example.com
      - "@[email protected]"
      - /spam-ring\.example\..*/
    

    Moderation rules also apply retroactively — interactions already stored are filtered at render time. Blocked ActivityPub followers are excluded from fan-out delivery and hidden from the public follower count, but their records are preserved so they can be automatically reinstated if you change your rules.

    Email Notifications

    Configure SMTP settings and Madblog will notify you by email whenever a new Webmention or ActivityPub interaction arrives — likes, boosts, replies, mentions, and quotes:

    author_email: [email protected]
    smtp_server: smtp.example.com
    smtp_username: [email protected]
    smtp_password: your-password
    

    Progressive Web App

    Madblog is installable as a PWA, with offline access and a native-like experience on supported devices. A service worker handles stale-while-revalidate caching with background sync for retries.

    Raw Markdown Access

    Append .md to any article URL to get the raw Markdown source:

    https://myblog.example.com/article/my-post.md
    

    Useful for readers who prefer plain text, or for tools that consume Markdown directly.

    Reusable Libraries

    Two key subsystems of Madblog have been extracted into standalone, reusable Python libraries. If you're building a Python web application and want to add decentralized federation support, you can use them directly — no need to adopt Madblog itself.

    Webmentions

    Webmentions is a general-purpose Python library for sending and receiving Webmentions. It comes with framework adapters for FastAPI, Flask, and Tornado, pluggable storage backends (SQLAlchemy or custom), filesystem monitoring for auto-sending mentions when files change, full microformats2 parsing, and built-in HTML rendering for displaying mentions on your pages.

    Adding Webmentions to a FastAPI app:

    from fastapi import FastAPI
    from webmentions import WebmentionsHandler
    from webmentions.storage.adapters.db import init_db_storage
    from webmentions.server.adapters.fastapi import bind_webmentions
    
    app = FastAPI()
    storage = init_db_storage(engine="sqlite:////tmp/webmentions.db")
    handler = WebmentionsHandler(storage=storage, base_url="https://example.com")
    bind_webmentions(app, handler)
    

    That's it — your app now has a /webmentions endpoint for receiving mentions, a Link header advertising it on every response, and a storage layer for persisting them. See the full documentation for details on sending mentions, custom storage, moderation, and rendering.

    Pubby

    Pubby is a general-purpose Python library for adding ActivityPub federation to any web application. It handles inbox processing, outbox delivery with concurrent fan-out, HTTP Signatures, WebFinger/NodeInfo discovery, interaction storage, a Mastodon-compatible API, and framework adapters for FastAPI, Flask, and Tornado.

    Adding ActivityPub to a FastAPI app:

    from fastapi import FastAPI
    from pubby import ActivityPubHandler, Object
    from pubby.crypto import generate_rsa_keypair
    from pubby.storage.adapters.db import init_db_storage
    from pubby.server.adapters.fastapi import bind_activitypub
    
    app = FastAPI()
    storage = init_db_storage("sqlite:////tmp/pubby.db")
    private_key, _ = generate_rsa_keypair()
    
    handler = ActivityPubHandler(
        storage=storage,
        actor_config={
            "base_url": "https://example.com",
            "username": "blog",
            "name": "My Blog",
            "summary": "A blog with ActivityPub support",
        },
        private_key=private_key,
    )
    
    bind_activitypub(app, handler)
    
    # Publish a post to all followers
    handler.publish_object(Object(
        id="https://example.com/posts/hello",
        type="Note",
        content="<p>Hello from the Fediverse!</p>",
        url="https://example.com/posts/hello",
        attributed_to="https://example.com/ap/actor",
    ))
    

    Optionally, you can also expose a Mastodon-compatible API so that Mastodon clients and crawlers can discover your instance and browse statuses:

    from pubby.server.adapters.fastapi_mastodon import bind_mastodon_api
    
    bind_mastodon_api(
        app,
        handler,
        title="My Blog",
        description="A blog with ActivityPub support",
    )
    

    Both libraries follow the same design philosophy: provide the protocol plumbing so you can wire it into your existing application with minimal ceremony. Storage is pluggable (SQLAlchemy, file-based, or bring-your-own), framework binding is a single function call, and the core logic is framework-agnostic. See the full documentation for Pubby and Webmentions.

    Links

    Madblog is open-source under the AGPL-3.0-only license. The source code, issue tracker, and full documentation are available at git.fabiomanganiello.com/madblog.

  18. Test post

    A test post to quickly check that #activitypub federation and #markdown rendering work on #madblog.

    A full blog article should be coming soon.

    Big shout to @[email protected] and @[email protected] to see if they get a notification!

    👋 @[email protected]

  19. Har opskrifter på grillet gås, and og flæskesteg på min gamle madblog....behøver jeg at sige at 80% af årets trafik til siden er i december måned med top i dag eller i morgen

    #bloggerliv #madblog #grillkokkerier #dervarengang

  20. A new version of #madblog is available! 🎉You can either clone it from here git.platypush.tech/blacklight/ or install it via `pip install madblog`.

    It now comes with #PWA support out of the box - manually creating a `manifest.json` is no longer required. So your own blog or web notebook can easily be installed as a PWA with zero additional configuration - yay!

    For those who aren't familiar with it, madblog is a platform I developed to have a simple but good-looking blog with zero JS that is *really* Markdown-based.

    When I say Markdown-based, I usually don't mean "it has a WYSIWYG editor that supports Markdown and will store your data on a database behind your back".

    No, I really mean "you create your directory with Markdown files, run madblog to use it as a content directory, and nothing else is required".

    If your blog pages are stored as Markdown files in a git repo, then running your blog somewhere is as simple as cloning the repo, creating a simple `config.yaml` in it, and running `madblog blog-dir`.

    It currently powers both my blogs (blog.platypush.tech and blog.fabiomanganiello.com).

    Ideas and feedback are welcome!

  21. @kev if you're into Markdown-based blogging you could consider take a look at #madblog git.platypush.tech/blacklight/.

    It's a platform that I started a while ago (and it currently powers all three of my blogs) for some of the reasons you just outlined: existing blog platform either come loaded with heavy and useless JS, or they have a too spartan design and offer no way of creating new content outside of their UI (this includes WriteFreely, unfortunately). My need was as simple as "I want to write all of my articles in Markdown, just have some simple headers in the file to provide the metadata (article title, author, banner image...), let a piece or software serve that Markdown from that folder, and the output should be a blog that looks good and that already builds a nice index for the articles in the style of Medium, and it should directly generate an RSS feed ". Oh, and with native LaTeX support - but that's just a geek feature I wanted. Zero databases involved, zero JavaScript involved.

    If your use-case falls along those lines, then you may give it a try too :) the only thing it doesn't have yet when compared to WriteFreely is Fediverse login/integration - but even in the case of WF the integration is still very basic.