Mastodon のインスタンス運営をする上で、Mastodon の設定が悪いとリモートフォローのユーザーの投稿がある日突然見えなくなることがあります。逆に相手サーバーの設定が悪いとせっかくリモートフォローしてくれたユーザーの投稿が届かなくなります。原因はいくつかあって、主に
- 受信側の購読の更新設定が出来ていなくて7日で期限が切れた場合
- 受信側サーバーのエラー時に送信側が投稿し購読が解除された場合
- 受信側か送信側の SSL の Mastodon への設定ミス
の3つが挙げられます。
まず、なぜそもそも購読とか期限とか、ややこしいことが必要なのでしょうか?
それは、Mastodon 等の OStatus を使ったSNSでは、異なるインスタンス間の通信をする上で成りすましを防ぐために署名の鍵を7日間で更新しながらポストを送る必要があるからです。その部分を Mastodon は PubSubHubbub という push 通知の方式を使って実装されていて、大まかには下記のような仕組みになっています。
前提として、server1.com 上のユーザー user1 が、server2.com 上のユーザー user2 の投稿を読みたくなってリモートフォローしたとします。
この場合、リモートフォローボタンを押したときに、server1.com から server2.com へ購読申請(Subscribe)が届きます。流れる情報には、
-
hub.topic
に読みたいユーザーの投稿の URL -
hub.callback
に投稿があった時に呼んでほしい callback URL -
hub.secret
に署名をするときの鍵
という情報が含まれます。callback URL には id という数字(例では{id2}
)が含まれていて、これは server1.com 上のリストの中の user2 を示す番号です。購読申請を受けた server2.com は、callback URL と署名の鍵 secret1 を保存します。(その直後にcallback URL の検証などの通信もなされます)リモートフォローのときに行われる一連の手続き(Subscribe)はこれで完了です。
次に、user2 から実際の投稿(post)があったときの動きです。user2 はSubscribe 時に設定された callback URL に向けて body に投稿本文を入れて送ります。このとき、この本文を先ほどの鍵 secret1 をキーとして作ったハッシュが署名のための付加情報として送られます。
この鍵は、成りすましを防ぐために、7日間で更新されます。7日以上経った鍵はクラックされている可能性があるので捨てられるというわけです。更新は受信側の方がもう一度購読申請(Subscribe)を行うことでなされます。この更新は主に受信側で cron などのスケジューラーによって行われます。コマンドは SubscribeService.new.call(Account.find({id2}))
ですが、mastodon では、mastodon:push:reflesh
や mastodon:daily
などのコマンドを叩くことによって期限が1日未満になっているユーザーを自動で検出して再申請するようになっています。
見えなくなるケースの1つ目は、受信側でこの購読再申請のスケジューリングをしていない場合です。この場合、7日経つと知らない間に user2 の投稿が user1 のホームタイムラインや server1.com の連合タイムラインに現れなくなります。これがまた、 server1 のローカルユーザーの投稿や、期限が切れていない server2.com 上のリモートユーザーの投稿はちゃんと流れるので、user2 だけの投稿が見えなくなっていることになかなか気づきにくいのです。
これを復旧するには、server1.com の方から SubscribeService.new.call(Account.find({id2}))
を実行するか、コマンド mastodon:push:reflesh
や mastodon:daily
を実行する必要があります。また、今後も同じことが起こるので、/etc/cron.d/
や crontab にこれらの実行を1日に2回以上入れてやるとよいです。(1日2回以上なのは、ラスト1日からやっと期限切れの検出がはじまるから。)
% ubuntu の例:
server1$ sudo vim /etc/cron.d/mastodon
RAILS_ENV=production
12 3,6 * * * root cd /var/www/mastodon/ && docker-compose run --rm web rake mastodon:daily
42 3 * * 1 root cd /var/www/mastodon/ && docker-compose run --rm web rake mastodon:media:remove_remote
12 4 23 * * root systemctl stop nginx && /opt/letsencrypt/letsencrypt-auto renew --force-renew && systemctl start nginx
1行目(mastodon:daily のある行) がその設定です。docker などで自動でやってくれると忘れないのですが。ついでに、忘れやすい設定として3行目の SSL 証明書の更新があります。これも忘れると90日で期限が切れます。3行目のは letsencrypt を使った更新例です。他の証明書を使っているときはモディファイしてください。
見えなくなる次のケースとして、受信側のサーバーでメンテナンスなどをしているときに、運悪くそのときに server2 からの user2 の投稿が行われてしまったケースです。server error 3xx や 4xx などが出ると即時に送信側で更新解除がなされ、購読していない状態に戻ってしまいます。(nginx の出す 503 bad gateway などの時は大丈夫です。)
受信側でもそれが起こったかどうかが直ぐには分からず、
cat /log/var/nginx/error.log | grep /api/subscriptions/ | egrep '" [34][0-9][0-9] ' | grep -v '" 429 '
などで調べると分かることが Mastodonのサーバ間通信が切れた場合のリカバリ で紹介されています。
この場合が起こったときは、受信側で SubscribeService.new.call(Account.find({id2}))
を実行するか、
期限切れ1日前以降に mastodon:push:reflesh
か mastodon:daily
を実行することで復旧できます。
最後に、MastodonのSSLの設定が悪いケースです。送信側、または、受信側のサーバーの .env.production の LOCAL_HTTPS
が false
になっているのに https を使っていると、リモートフォロー後に相手に投稿が届かない現象が起きます。この場合もローカルユーザーの投稿だけは見えるので、気づきにくいかもしれません。リモートフォローを使って初めて気付きます。LOCAL_HTTPS
が true
になっていることを確認して下さい。
server1$ sudo vim /var/www/mastodon/.env.production
# Federation
...
LOCAL_HTTPS=true
...
参考