Multiple mastodon aliases to domain using Cloudflare Pages
Jul 8, 2023Introduction #
Recently, I’ve begun utilizing Mastodon as my go-to social media platform for technical queries. I’ve found that while Mastodon’s decentralized nature – a core aspect of the Fediverse – is attractive, it also brings about some complexities. Similar to how email addresses work, a user’s profile on Mastodon is tied to their instance’s domain.
In my journey, I discovered Fosstodon, a server with a community that aligns with my perspectives. I wished to tie my Fosstodon’s account to my personal domain and username, essentially making it [email protected]
. For my website, I use the superb Hugo static site generator and deploy it to CloudFlare Pages, but it doesn’t have any server-side logic to resolve the name.
Following, this goal came with a challenge: I had to find a solution without any server-side logic to resolve the name.
The Problem #
I came across a service named WebFinger in my search for a solution. WebFinger utilizes the fediverse specification to resolve names. When I input my Fosstodon’s account `[email protected]`` into a search field, it demonstrates how the name gets resolved.
It does these two things:
04:15:24 Looking up WebFinger data for acct:[email protected]
04:15:24 GET https://fosstodon.org/.well-known/webfinger?resource=acct%3Aaohorodnyk%40fosstodon.org
From my analysis, I concluded that for an alias to my Fosstodon’s account, the same JSON should be resolved by this path: /.well-known/webfinger?resource=acct%3Ame%40aohorodnyk.com
.
The simplest approach would be to create a file /.well-known/webfinger with the content from Fosstodon. The downside is that all users in my domain would be resolved with the same account. So, I needed to find a way to resolve different files by different GET parameters to the same path.
The solution #
My search for a way to apply minimal logic to resolve different files by different GET parameters to the same path was initially fruitless. The only available solutions online involved using CloudFlare Workers/CloudFlare Functions.
Reluctantly, I was considering using functions. However, the unpredictable pricing of serverless solutions was a deterrent. I didn’t want to incur costs for my minimalist needs.
After several failed attempts, including trying to create a file with the full name /.well-known/webfinger?resource=acct%3Ame%40aohorodnyk.com
, I found a ray of hope in CloudFlare Transform Rules. This feature lets us create rules to transform requests to our server.
CloudFlare Transform Rules #
The concept was to develop a rule that could parse /.well-known/webfinger?resource=acct%3Ame%40aohorodnyk.com
and transform it into a unique file in CloudFlare Pages. The main file /.well-known/webfinger
wouldn’t exist at all, ensuring all other requests returned a 404 as expected.
Rule Requirements #
While it might not be overly critical, it’s beneficial to lay down requirements for our solution:
- The request
/.well-known/webfinger?resource=acct%3Ame%40aohorodnyk.com
must resolve our JSON - The same JSON should be resolved on the request
/.well-known/webfinger?resource=acct%3Ame%40aohorodnyk.com&format=json
- For ALL other requests, a 404 error should be returned
Successful Implementation #
In CloudFlare’s admin page, I formulated a rule with specific settings and the action to transform the request to the file /.well-known/webfinger-aohorodnyk.json
Expression preview: (http.request.uri.path eq "/.well-known/webfinger" and http.request.uri.query contains "resource=acct:[email protected]") or (http.request.uri.path eq "/.well-known/webfinger" and http.request.uri.query eq "resource=acct%3Ame%40aohorodnyk.com")
.
And the action is to transform the request to the file /.well-known/webfinger-aohorodnyk.json
.
Evaluation #
Upon saving the rules, I ran various positive and negative test cases using curlie
and found the results to be successful:
# Positive test cases
$ curlie "https://aohorodnyk.com/.well-known/webfinger?resource=acct%3Ame%40aohorodnyk.com"
HTTP/2 200
...
{
...
}
$ curlie "https://aohorodnyk.com/.well-known/webfinger?resource=acct:[email protected]"
HTTP/2 200
...
{
...
}
# Negative test cases
$ curlie "https://aohorodnyk.com/.well-known/webfinger?resource=acct%3Aame%40aohorodnyk.com" # wrong username with prefix `a`
HTTP/2 404
...
$ curlie "https://aohorodnyk.com/.well-known/webfinger?resource=acct%3Amea%40aohorodnyk.com" # wrong username with suffix `a`
HTTP/2 404
...
$ curlie "https://aohorodnyk.com/.well-known/webfinger?resource=acct%3Ame%40ohorodnyk.com" # wrong domain
HTTP/2 404
...
$ curlie "https://aohorodnyk.com/.well-known/webfinger?resource=acct%3Ame%40aohorodnyk.co" # wrong domain
HTTP/2 404
...
Conclusion #
Overall, the solution proved to be straightforward, efficient, cost-free, and operational. Moreover, it demonstrated excellent scalability for multiple users on the same domain.
By the way, since our topic is built around Mastodon, I invite you to subscribe on me and stay on touch. My account is [email protected] ([email protected])