Skip to content

Instantly share code, notes, and snippets.

@gwire
Last active November 19, 2022 10:34
Show Gist options
  • Save gwire/0522c3006ff731cf9d17913fb73fb776 to your computer and use it in GitHub Desktop.
Save gwire/0522c3006ff731cf9d17913fb73fb776 to your computer and use it in GitHub Desktop.
A simple webfinger service using nginx

My assumption is that you should be able to discover Mastodon accounts by searching for email addresses, which should in turn query webfinger.

So for a domain that isn't hosting Mastodon, you can set up a webfinger server. Or you can just hand code some json files and serve them using nginx.

Rather than look into installing a webfinger server, I just initially want to serve up the json files directly from nginx.

  • Set up a redirect under example.com (as suggested in RFC 7033)
  location = /.well-known/host-meta {
    default_type "application/xrd+xml";
    add_header Cache-Control "max-age=259200, public";
    return 200 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<XRD xmlns=\"http://docs.oasis-open.org/ns/xri/xrd-1.0\">\n<Link rel=\"lrdd\" template=\"https://$host/.well-known/webfinger?resource={uri}\"/>\n</XRD>\n";
  }
  
  location /.well-known/webfinger {
    add_header Access-Control-Allow-Origin "*";
    return 307 https://finger.example.com/example.com/webfinger$is_args$args;
  }
  • Then set up a new domain finger.example.com
## Note this process isn't safe for non-ascii usernames and domains, and would need to be modifed to support them.

## needs the perl module for nginx to be active
## where query is "resource=acct:bob@example.com" this should return acct/example.com/bob.json
perl_set $user_json 'sub {
 my $r = shift;
 my $wf_resource_json = $r->args;
 $wf_resource_json = lc($wf_resource_json);
 $wf_resource_json =~ s/resource=(.+)(\:|%3a)(.+)(@|%40)(.+)($|&)/$1\/$5\/$3.json/g;
 $wf_resource_json =~ s/[^a-z0-9\.\/\-\+_]//g;
 return $wf_resource_json;
}';

## map sort of works but falls over if non-lowercase requests are made
## and there's no built-in string normalisation
#map $arg_resource $user_json {
#default acct/none;
#~(.+)(\:|%3[Aa])(.+)(@|%40)(.+) $1/$5/$3.json;
#}

server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  server_name finger.example.com;

  ## certificates, etc

  location ~ /webfinger$ {
    add_header Access-Control-Allow-Origin "*";
    default_type "application/jrd+json";
    types { application/jrd+json json; }
    root /srv/webfinger;
    try_files /$user_json =404;
  }
}
  • Then create the file /srv/webfinger/acct/example.com/alice.json
{
  "subject": "acct:alice@example.com",
  "links": [
    {
      "rel": "http://webfinger.net/rel/profile-page",
      "type": "text/html",
      "href": "https://mastodon.example/@alice"
    },
    {
      "rel": "self",
      "type": "application/activity+json",
      "href": "https://mastodon.example/users/alice"
    }
  ]
}
  • This file should be returned by a (redirect-following) request for https://example.com/.well-known/webfinger?resource=acct:alice@example.com.

In theory a search on any Mastodon instance for alice@example.com should return the profile for @alice@mastodon.example.

In practice this seems to work, but sporadically. Sometimes I see the webfinger requests in the logs, but often they fail to appear.

It's possible, of course, to redirect the webfinger requests directly to a Mastodon server - but in theory the webfinger protocol can be used to point to many different resources, so it might be better to keep these managed directly?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment