If you are setting up an ActivityPub (Mastodon or GotoSocial) server, and want your domain to be at the “Apex” of your domain, and your domain is already hosting an existing website, you’ll need to do some additional setup. GotoSocial calls this a “Split Domain deployment”.
In my case, I wanted my ActivityPub user to be @blake@blakesmith.me, but my website is already hosted at blakesmith.me
, meaning my ActivityPub server (GotoSocial in this case) needs a little extra configuration.
The setup is:
- Host domain:
social.blakesmith.me
- Account domain:
blakesmith.me
Here’s my NixOS module that configures GotoSocial (a minimal ActivityPub server, great for small and single user instances) with the split domain on my server. Notice the host
and account-domain
configuration:
We put nginx in front of GotoSocial, and setup a LetsEncrypt TLS cert as well (required for ActivityPub). This should all work great once DNS for social.blakesmith.me
is pointed at the NixOS server. The GotoSocial daemon is reachable at social.blakesmith.me
, but is configured to have usernames with blakesmith.me
.
My website, blakesmith.me
is hosted via an S3 bucket, with Cloudfront in front of it. We need to configure the S3 bucket for blakesmith.me
to redirect all requests to the /.well-known
route prefix to social.blakesmith.me
. Here’s the terraform necessary:
The routing_rules is the most important part: Any route to the bucket that is prefixed with .well-known
will be redirected to social.blakesmith.me
. ActivityPub / Mastodon uses the WebFinger protocol as a way to resolve profile and server information for a given Mastodon handle.
Let’s test it:
$ curl -v "https://blakesmith.me/.well-known/webfinger?resource=acct:blake@blakesmith.me"
> GET /.well-known/webfinger?resource=acct:blake@blakesmith.me HTTP/2
> Host: blakesmith.me
> User-Agent: curl/8.4.0
> Accept: */*
>
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
< HTTP/2 301
< content-length: 0
< location: https://social.blakesmith.me/.well-known/webfinger?resource=acct:blake@blakesmith.me
< date: Sat, 17 Feb 2024 18:02:11 GMT
< server: AmazonS3
< x-cache: Hit from cloudfront
< via: 1.1 4076c139caa3b19374b9d2d1784ca5e0.cloudfront.net (CloudFront)
< x-amz-cf-pop: ORD56-P4
< x-amz-cf-id: XN5GXTM2fhACc4ZWmRbs2PMKmxEMeI-3yj0GZJ_orlLAp655feXVZQ==
< age: 3
<
* Connection #0 to host blakesmith.me left intact
It’s working if you get a valid redirect to your host domain server! If we follow redirects, we’ll hit the ActivityPub server hosted at social.blakesmith.me
:
$ curl -L "https://blakesmith.me/.well-known/webfinger?resource=acct:blake@blakesmith.me" | jq .
{
"subject": "acct:blake@blakesmith.me",
"aliases": [
"https://social.blakesmith.me/users/blake",
"https://social.blakesmith.me/@blake"
],
"links": [
{
"rel": "http://webfinger.net/rel/profile-page",
"type": "text/html",
"href": "https://social.blakesmith.me/@blake"
},
{
"rel": "self",
"type": "application/activity+json",
"href": "https://social.blakesmith.me/users/blake"
}
]
}
If all is well, other users should be able to follow you using the account domain as your username (In my case: @blake@blakesmith.me).
One pitfall that tripped me up for awhile: if you have Cloudfront in front of your S3 bucket, like I do, you have to configure your Cloudfront origin using a custom origin and the S3 website endpoint, NOT the bucket endpoint. Otherwise, you’ll get “The specified key does not exist” errors when trying to access the webfinger resource at your account domain.
The relevant terraform setup for the Cloudfront distribution looks like this (notice how the bucket origin is configured with a custom_origin_config
):
Feel free to follow me at @blake@blakesmith.me on ActivityPub!