implementing self-hosted webmentions
Origin
I discovered Webmention reading the IndieWeb specification.
No API key. No OAuth. No third-party platform accounts. Just two URLs:
- Source: who linked to me
- Target: my page
The source server sends a POST request to my /webmention endpoint.
My server verifies that the link really exists.
If it exists, I save the mention.
If it does not exist, I discard it.
That is it.
No intermediaries. No algorithms. No platform lock-in.
The Connection
Why does the Monolith archive this? Because Webmention is pure sovereignty.
When someone links to my article on another IndieWeb site, I know. Not because Facebook tells me. Not because Twitter notifies me. But because the protocol itself delivers it to me.
It is the decentralized web working as it should:
- You publish on your domain.
- I publish on my domain.
- If you link to me, I know.
- Neither of us depends on a central platform.
The Challenge
The technical challenge was implementing the server on OpenBSD.
There is no “install and forget” plugin. I had to:
- Configure relayd to forward
/webmentionto Node.js (port 3000) - Write the Node script that verifies links
- Save mentions in a local JSON
- Expose an
/api/mentionsAPI to read them - Display mentions in the Astro frontend
The psychological challenge was accepting that not all mentions arrive.
If a site does not support Webmention, I do not know. If someone links to me on Medium or LinkedIn, I receive nothing.
But it is a limit I willingly accept. I prefer 10 mentions on sovereign sites to 1000 likes on platforms that own me.
Peace of Mind
Now that I have written this, I have clarified the value of Webmention:
- They are direct notifications, without intermediaries.
- They are verified, not spoofable.
- They are under my control (my server, my database).
- They are interoperable (anyone can implement them).
Peace of Mind comes from knowing that every mention I receive is an act of respect. Someone took the time to link to me on their own domain, not to click “share” on a platform button.
The Monolith is not an island. It is a node in the network.
Technical Note:
- Endpoint: POST /webmention (source + target)
- Verification: GET source → search for target in content
- Storage: /var/www/webmention/data/mentions.json
- API: GET /api/mentions?target=URL
- Frontend: Astro Webmentions.astro component (client-side fetch)
- Cache: 5 minutes in localStorage for performance
- Zero dependencies: all self-hosted on OpenBSD