Multiple mastodon aliases to domain using Cloudflare Pages


Introduction #

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").

Working rules

And the action is to transform the request to the file /.well-known/webfinger-aohorodnyk.json.

Transformation rules

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])