noellabo's tech blog

@noellaboの技術ブログ

リレーサーバの内部の仕組み

リレーは、ActivityPubを用いて、Activityを中継する比較的単純なサーバプログラムです。

MastodonやPleromaなどのActivityPubサーバからリレーに接続を行い、お互いにやりとりできることを確認します。接続が確立できたら、Activityの送受信を開始します。

リレーへの接続

リレーへの接続は、Mastodon方式とPleroma方式があります。

Mastodon方式では、特殊なフォローリクエストで参加が確立します。

  • 【Mastodon】ローカルの任意のactorを使い、リレーのinboxへ、FollowをPOSTする
  • 【リレー】Followの宛先がpublicコレクションであれば、リレー参加表明と判断する
  • 【リレー】MastodonのFollowを送信してきたActorのinboxへ、AcceptをPOSTする
  • 【リレー】AcceptのPOSTでエラーにならなければ、リレーはMastodonを参加リストに追加し、投稿の受付と配信を開始する
  • 【Mastodon】Acceptを受信したら、リレーが有効になったと判断し、投稿の受付と配信を開始する

Pleroma方式では、特殊なActorによるフォローリクエストとフォローバックにより参加が確立します。

  • 【Pleroma】リレーのactorを取得し、inboxのURLや公開鍵を取得する
  • 【Pleroma】特殊なActorである@relayを使い、リレーのinboxへ、FollowをPOSTする
  • 【リレー】Followの宛先がリレーのactorで、Pleromaのリレー用actor(@relay)からのリクエストであれば、リレーへの参加表明と判断する
  • 【リレー】Pleromaの@relayのinboxへ、(受け取ったFollowに対する)AcceptをPOSTする
  • 【リレー】Pleromaの@relayのinboxへ、FollowをPOSTする
  • 【Pleroma】Followを受信したら、リレーへAcceptをPOSTする
  • 【リレー】PleromaからAcceptを受信したら、リレーはPleromaを参加リストに追加し、投稿の受付と配信を開始する
  • 【Pleroma】送信したFollowがAcceptされ、送信したAcceptが受理されたら、リレーが有効になったと判断し、投稿の受付と配信を開始する

リレーとの接続解除

いずれの方式でも、解除はフォロー解除により行われます。

  • 【Mastodon・Pleroma】リレーのinboxに、(参加時に送った)Follow ActivityのUndoをPOSTする

投稿の配送

投稿の配送は、Activityをそのまま転送する方式と、Announceする方式があります。

Mastodonは、Activityをそのまま転送します。 Pleromaは、Announceにより間接的に投稿の配送を行います。

Announceによる配送

発信サーバから受信サーバへ直接配送する場合は、HTTP署名により投稿の主体の把握と改ざんの確認を行っています。

ところが、リレーによる配送は、発信者のサーバと受信者のサーバの間に、無関係の第三者が割り込むことになるため、HTTP署名では確認がとれません。

Linked Data SignaturesによりActivityに署名を行えば、配送経路によらずにActivityが改ざんされていないか確認することができますが、PleromaはLinked Data Signaturesに対応していないため、単純に転送することができません。

そこで、配送したい投稿を受け取ったら、リレーのActorがAnnounceとして発信することで、リレーから受信者へのActivityへと変換します。こうすれば、リレーと受信者のサーバのHTTP署名だけで確認を取ることができます。

Announceを受け取った受信者のサーバは、自ら送信者のサーバから投稿内容を取得します。

Announceによる配送の負荷

リレーに100のサーバが参加しているとします。

Activityをそのまま転送する場合、送信者がリレーに送る1回と、リレーから参加者へ送る100回のリクエストになります。

Announceを使った配送の場合、上記に加えて、リレー参加サーバから送信者のサーバへ(内容を取得するための)100回のリクエストが行われます。この取得のリクエストは非常に短い時間に集中して行われるため、送信者のサーバの負担が重くなります。適切にキャッシュするようにしてあれば処理能力的には十分に対応できますが、転送量の増加(約100倍)は避けられません。リレー参加サーバにしても、受け取るだけでなく取得も必要になるため、約2倍の負荷が掛かります。

Announceは、ブースト・リピート・リノートなどユーザーが利用する通常のActivityですが、リレーの場合は公開投稿すべてをAnnounceすることになるため、留意しておきましょう。

pub-relayの場合

Mastodon用のリレーとして開発されたものであるため、基本的にすべてMastodon方式です。v0.2.0から、参加方法はMastodonとPleromaの両方式に対応し、Linked Data Signaturesで署名されている投稿はそのまま配送、署名されていない投稿はAnnounceに変換して配送しています。

ActivityRelayの場合

Pleroma用のリレーとして開発されたものですが、Mastodonの参加方法にも対応しています。Announceによって配送しています。

補足

publicコレクション

ActivityPubにおいて、投稿の宛先などにhttps://www.w3.org/ns/activitystreams#Publicと指定すると、誰でも閲覧できる公開の投稿になります。ActivityStreamにおけるコレクションの一種です。Mastodonのリレー参加方式では、Followのobjectとしてこれを指定することで、リレーの公開投稿すべてをフォローする、という表現を行っています。

Mastodonのインスタンスアクター

Mastodonがリレーに参加するFollowの際には、サーバ間でやりとりして、最終的にshared inboxのURLを通知することが目的であるため、究極的にはどのローカルユーザーを使ってやりとりしても同じ結果になります。そのため、リレー対応の初期の実装では、実際に、適当なユーザーを一つ選んで使うという実装になっていました。

現在のMastodonでは、そういった用途に用いるための専用のActor(インスタンスアクター)が用意されていて、それが使われています。

Mastodonのインスタンスアクターは、id:-99、usernameがドメイン名、Applicationタイプの特殊なユーザーで、組み込みで実装されています。

Pleromaのrelay Actor

Pleromaの場合、各サーバにリレー専用のユーザーが存在します。nameはPleroma、preferredUsernameはrelay、ApplicationタイプはApplicationタイプの特殊なユーザーで、組み込みで実装されています。

ユーザーのpublicKey

Activityをやり取りしたり、投稿を取得しにいく際には、HTTP署名を用いて、HTTPリクエストを署名しています。署名付きのリクエストを行うことで、単純なHTTPと違って、ユーザー情報・権限付きのリクエストが行えます。

この際、署名したユーザーのpublicKeyをまだ知らない場合は、そのユーザーのpublicKeyを直接その所属サーバに取得しに行きます。この情報は保存しておけば何度も取りに行かなくて済むので、通常はユーザー情報とともに保存しておきます。

pub-relayはそのあたりの実装が雑で、毎回取得しにいく実装になっています。v0.2.0以降は、redisに2日だけキャッシュするようになっていますが、比較的短期間で破棄しています。

最初に取得したpublicKeyで署名の確認が行えない、publicKeyが変更になっているケースがあります。この時、最初のpublicKeyこそが正しく、新しいpublicKeyを使っているユーザーはニセモノかもしれません。あるいは、一度破棄されたドメインで、再度新規にサーバを立ち上げただけかもしれません。privateKeyが流出して、セキュリティ問題により変更したのかもしれません。

一般に、保存してある古いpublickKeyを破棄して、新しいpublickKeyを受け入れる判断は、諸事情勘案の上、サーバ管理者が行った方が良いかと思いますが、リレーなどの人為的判断があまり介入しないサーバにおいてこれをどう実装するかは、それぞれの考え方によるところです。