Mastodon移住の話からMastodonメディアをwasabiという安いオブジェクトストレージに移管した話まで

# 当記事について

この記事はMastodonアドベントカレンダー 5日目の記事です(遅刻すみません・・・)

なお、最初の方は申し訳ないながらポエムが多いので、wasabiをMastodonのオブジェクトストレージにした話だけ見たい方は[オブジェクトストレージwasabi導入について](#オブジェクトストレージwasabi導入について)まで飛んでください。

# 私について

## 自己紹介

ピトルと申します。某北海道の情報系大学の２回目の４年生をしているしがない学生です。元[https://mstdn.fun](https://mstdn.fun)の住民でした。現在は(決済オタク丼|決済丼)[mstdn.kessai-otaku.club](https://mstdn.kessai-otaku.club)の管理人をしております。

## Mastodonとの関わりについて

8月ころの、それこそTwitterでUserStreamの廃止を契機に、Mastodonにチラチラ来るようになりました。多分akkiesoft氏([Mastodon](https://social.mikutter.hachune.net/@akkiesoft))のアカウントプロフィールをちらっと覗いた時にMastodonに完全移住したとのツイートを見て、「なるほど、そんなにMastodon心地いいところなのか」と大昔に作ったmstdn.jpのアカウント(今はアカウント削除済)を見てみると、昔TL見たときよりも賑やかになったなという印象を受け、また、[末代](https://mstdn.maud.io)の住民が楽しそうだったり、我が大学の広義の先輩であるえじょ猫氏([Matstodon](https://mstdn.nere9.help/@ejo090))がTwitterに顔だしてた時代のノリでnullをつぶやいていて楽しそうだなと思いました。

また、Twitterはどんどん文化が進化して、例えばバズったツイートのリプ欄はYoutubeのコメント欄を同じで意見やコメントを述べる場になる、バズったツイートには自分の宣伝ツイートをリプライで吊り下げるなど、渡しとしてはバズりを重視するSNSとしてはどんどん進化していると感じていますが、それと同時に、自分のいるべき場所はここでは無いとも感じるようになってきました。

そんな考えが改まるタイミングと重なったこともあり、移住の決心が付き、Twitterからふっと姿を消しました。でもたまーに見ないとかわいい絵の収集やニュースなどが入ってこなくなる為、暇つぶしにすこし見る程度でTwitterにもたまーに浮上しています。

# 決済丼の開設

## インスタンスドメインにブランドを感じていた頃

mstdn.jpはユーザー数が多いので大体皆使っているのですが、ローカルTLの流れは早いし、トゥートの中身もTwitterと変わりなく、面白くありませんでした。その一方、[https://mstdn.nere9.help](mstdn.nere9.help)は少人数で自分の知ってる人が管理人をしていて、「mstdn.funの住民だったみんなおいでよ」的文言を見て移住しました。

## 自分たちの趣味の輪でインスタンスを建てたい！

nere9でのnullをトゥートし続ける生活は昔のTwitterのようでとても素晴らしいものでしたが、やはり根はエンジニア、自分でもインスタンスを建ててみたくなったのです。でも、おひとりさまインスタンスだとドメインブランド力が弱い(？)と感じ、ならば、趣味のインスタンスを立てようじゃないかと考えました。

そこで目をつけたのが決済クラスタです。決済クラスタとは、マクドナルドやローソンなどでNFCコンタクトレス決済をしたり、paypay導入日当日にわざわざ遠く離れた導入店舗に出向いて店員さんの目を丸くさせたりなど、決済周りの新しいこと、ライフハック、おもしろ機材などに目がない人たちの集まりです。実は私もTwitterを通じて交流があった人たちがいて、その人の誘いで決済クラスタの集まるLINEグループに招待され、自分も知らないような超ディープな情報がやりとりされていて、「これ、シェアできる情報はシェアするべきじゃないか」と思うようになり、決済クラスタの為のインスタンス、決済丼を建てることにしたのです。

#　決済丼のシステム構成について

## サーバースペック
https://mstdn.kessai-otaku.club/about/more からの引用です。
>
> ### メインサーバー
> - カゴヤのVPS KVM
> - OS Ubuntu 18.04.1LTS
> - CPU 2コア
> - RAM 2GB
> - SSD 50GB
> - 構築方法 非Docker(Standalone)
>
> ### メディアサーバー
> wasabi S3-compatible Cloud Storage
> ※アクティブユーザー数やトゥート数に合わせてスケールアップを行っていきます

上記のような構成になっており、メディアのみオブジェクトストレージ保管、それ以外をVPSで稼働させる構成を取っています。現在決済丼のアクティブユーザーが１−２名程度なので、サーバーを分けなくとも今の所問題も起きず、性能も十分に足りており、自分がバックエンド技術について疎いこともあり、この構成にしています。一時期Mastodonの全文検索対応に合わせてElasticsearchを入れましたが、メモリが少なく、需要も無いだろうということで今は全文検索を無効化しています。

# オブジェクトストレージwasabi導入について

## オブジェクトストレージとは

[富士通](http://www.fujitsu.com/jp/products/computing/storage/lib-f/tech/beginner/object-storage/)によると

> オブジェクトストレージはデータを「オブジェクト」という単位で扱う記憶装置です。 
ディレクトリ構造で管理するファイルストレージとは異なり、データサイズやデータ数の保存制限がないため、大容量データの保存に適しています。

だそうです。ようするにディレクトリ単位でのデータ管理ではなく、全てのデータをオブジェクトとして管理することで、ストレージ容量の概念にとらわれず許す限り大量の大容量のデータを扱うことが出来るストレージです。ローカルではなかなか実現出来ないこともあり、クラウドのSaaSとして展開されているものを使うことが多いです。AWSではS3、GCPではCloud Storageの名前で展開されています。

## Mastodonでオブジェクトストレージを使う意味

SNSの醍醐味は画像や動画だと思います。多分。

最初はVPSのストレージでどうにかなるっしょと思っていましたが、2週間立たずでメディアフォルダーの容量が10GBを突破した為、これでは1ヶ月持たないと思い、翌月までの保険としてVPSのSSD容量を30GB→50GBにアップしました。ただ、かごやクラウドVPSってストレージのスケールアップは可能だけどダウンは出来ないので、後々無駄に料金を上げてしまうことになってしまいました。

なので、もしインスタンス建てるのであれば、メディアとその他は分離したほうがいいと思います。

## wasabiとは

APIがAWS S3互換のオブジェクトストレージサービスです。何より利用料金が非常に安価であるのが特徴です。

- wasabi: [https://wasabi.com](https://wasabi.com/)

### 料金体系

#### wasabi

- アップロード料金、ダウンロード料金、通信料金は課金無し
- GBあたりの料金だと $0.0049 per GB/月、日本円で約0.55円
- TBあたりの料金だと $4.99 per TB/月、日本円で約564円

#### AWS S3 東京リージョン(50TB以内)

- リクエスト1000件あたり$0.00037~0.00047、(日本円0.05円前後)
- $0.025 per GB/月、日本円で約28.27円

AWS S3ですとAWS内で通信が完結する場合は通信料金の課金はありませんが、私みたいにVPSを使う場合は、別途料金が発生します。リクエスト料金抜きにしても、月あたりの使用量GB単価がAWSだと桁1つ料金が高くなってしまいます。一番安いリージョンでも$0.023 per GB/月なので、wasabiのやすさが目立ちますね。

#### 参考：各クラウドストレージサービス 1TB
- office365 solo 月1000円/月
- dropbox Plus 1200円/月

大衆向けクラウドストレージサービスよりも安いwasabiすごいですね・・・

というわけで、決済丼ではオブジェクトストレージとしてwasabiを選択しました。

# Mastodonのオブジェクトストレージとしてwasabiを接続する

英語ではありますが、なんとありがたいことにwasabiの中の人がMastodonのオブジェクトストレージとしてwasabiを選択するときの設定手順について書いている記事がありました。その節は大変お世話になりました。この記事の中身を参考に解説していきます。

[https://angristan.xyz/moving-mastodon-media-files-to-wasabi-object-storage/](https://angristan.xyz/moving-mastodon-media-files-to-wasabi-object-storage/)

## bucketを作る

まずは「CREATE BUCKET」からbucketを作りましょう。bucketとはすなわち保存するオブジェクトの塊と思ってもらえればと思います。器を作ると言った方がわかりやすいかな

![スクリーンショット 2018-12-06 16.56.53.png](https://qiita-image-store.s3.amazonaws.com/0/104876/f9e424de-364e-35c1-506a-035066ecaa03.png)

bucketの設定画面が開きます。bucket nameはbucketを操作するときの識別名、IDのようなものなので英数字でお好きに、regionは日本に近いほうがいいので「us-west-1」を選びましょう。

![スクリーンショット 2018-12-06 17.00.42.png](https://qiita-image-store.s3.amazonaws.com/0/104876/cb98a3bf-4599-c943-26a2-c843a1412f8e.png)

この次の画面はバージョン管理やLogging機能を有効化するか否かの選択なので、特に必要なければスルーしてbucket作成を完了してください。

その後、作成したbucketを選択して、設定画面を開いてください。

![スクリーンショット 2018-12-06 17.14.08.png](https://qiita-image-store.s3.amazonaws.com/0/104876/ce574b58-96cd-f416-9526-7e231d8b2271.png)

bucketの設定画面が出るはずです。上部に並ぶタブバーから```POLICIES```を選び、下記文字列をコピペしてください。{your-bucket-name}の部分には先程設定した自分のbucket nameを入れてください。
「mstdn-media-qiita」と設定したのであれば、```"Resource": "arn:aws:s3:::mstdn-media-qiita/*"```といった感じになります。終わったら```SAVE```ボタンを押しましょう。これによりこのbucketの中身に誰でもアクセスできるようになります。もちろん読みに来ることしか出来ません。

```
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AddPerm",
      "Effect": "Allow",
      "Principal": {
        "AWS": "*"
      },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::{your-bucket-name}/*"
    }
  ]
}
```
![スクリーンショット 2018-12-06 17.19.44.png](https://qiita-image-store.s3.amazonaws.com/0/104876/08dfcab2-06ca-da93-03ca-2f85f8c2ca09.png)

## Userの作成

要するにUNIXでいう権限ユーザーの作成みたいなものです。Userを作成して、Mastodonでトゥートを投稿する人達のためにbucketでデータの出し入れする権限を持つユーザーを作成しましょう。

Menuボタン(wasabiロゴ横のハンバーガーバーです)を押して、Userを選択。その後、```CREATE USER```を押しましょう。

![スクリーンショット 2018-12-06 17.08.14.png](https://qiita-image-store.s3.amazonaws.com/0/104876/274fa782-f4b1-374e-b77b-f5930160e5fe.png)

そして、bucketの同じようにユーザー名の設定をしていきます。```Access```の```Programmatic(create API key)````にチェックを入れておきます。終わったら次へ。

![スクリーンショット 2018-12-06 17.29.45.png](https://qiita-image-store.s3.amazonaws.com/0/104876/33c89ed6-46ec-bcb7-d9f5-167705654306.png)

次に、権限グループの設定画面になります。インスタンス1つだけであればわざわざ権限グループを設定する必要は無いのですが、もしもう1つインスタンス建てたくなった時の為に適当にmastodonなんてグループ作っときますか(名前は自由に決めてください)。

この次の画面はあとで設定するのでどんどん次に進んで```CREATE USER```を押してください。

![スクリーンショット 2018-12-06 17.34.42.png](https://qiita-image-store.s3.amazonaws.com/0/104876/310932a9-8c1c-6c73-aa11-fda21b4c3a77.png)

完了したら、Access KeyとSecret Keyが発行されます。2つとも必ずメモしておいてください。Mastodonで設定する時に必要です。とくにSecret Keyに関しては再発行出来ないので、忘れたらAPI key発行し直しになるので注意。

![スクリーンショット 2018-12-06 17.37.20.png](https://qiita-image-store.s3.amazonaws.com/0/104876/a052daab-1056-7122-e6f9-a7d9df63e1b8.png)

## Policyの設定

次に、この設定したユーザーやグループに書き込み権限を与えるための権限設定を行います。

```Policiesタブ```を選択し、```CREATE POLICY```を押します。

![スクリーンショット 2018-12-06 17.43.01.png](https://qiita-image-store.s3.amazonaws.com/0/104876/8810b41f-033c-ad05-c3bc-dbdbc05c938f.png)

次に、policy nameとpolicy documentを設定します。policy nameはお好きな名前を、policy documentには下記文字列をコピペしてください。{your-bucket-name}の部分には先程設定した自分のbucket nameを入れてください。
ここも先程と同じく、「mstdn-media-qiita」と設定したのであれば、```"Resource": "arn:aws:s3:::mstdn-media-qiita/*"```といった感じになります。終わったら```SAVE```ボタンを押しましょう。これで、この権限を設定したユーザーやグループからのAPIアクセスに対してデータの書き込み・読み取り・削除権限が付与されます。

```
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::{your-bucket-name}"
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:DeleteObject"
      ],
      "Resource": "arn:aws:s3:::{your-bucket-name}/*"
    }
  ]
}
```

SAVEしたら、グループに対して権限を付与しましょう。

左タブから```Groups```を選び、先程ユーザー作成時に作ったグループ(ここではmastodon)を選択します。ここにpolicyを設定します。まず、```USER```タブ内に先程作ったユーザー名が追加されているか確認します。サイトの不具合が無い限りここに先程作ったユーザー名(ここではmastoidon-qiita)が追加されているので、良ければ```PERMISSIONS```タブに移動します。

![スクリーンショット 2018-12-06 17.57.09.png](https://qiita-image-store.s3.amazonaws.com/0/104876/80d4fe57-a8f6-f518-889b-ad40a0d12017.png)

PERMISSIONSタブに先程設定したpolicyを設定して、グループ全体の権限を設定します。

```Add Policy To Group```と書かれてるボックスに先程作った権限名を入力して検索し、クリックして設定しましょう。```Policies attached to {グループ名}```にpolicyが追加されたのを確認して閉じます。

![スクリーンショット 2018-12-06 18.00.55.png](https://qiita-image-store.s3.amazonaws.com/0/104876/d5179588-0a6f-238c-c53b-e7a31a0d07ff.png)

これでwasabi側の設定は終わりです。次はMastodon側の設定です。

## Mastodon側の設定

※non-dockerを前提に解説しますので、dockerインストールの方は適宜置き換えてください。

Mastodonのディレクトリに移動し(non-dockerの場合はlive)、.env.productionを開きます。

そして、下記項目を追記します(多分コメントアウトされてる項目で存在するはずなので、コメントアウトを解除して書き換えればいいと思います)

```
S3_ENABLED=true
S3_BUCKET={bucket名}
AWS_ACCESS_KEY_ID={access key}
AWS_SECRET_ACCESS_KEY={secret key}
S3_REGION=us-west-1 # eastリージョンはus-east-1
S3_PROTOCOL=https
S3_HOSTNAME=s3.us-west-1.wasabisys.com # eastリージョンはs3.wasabisys.com
S3_ENDPOINT=https://s3.us-west-1.wasabisys.com # eastリージョンはhttps://s3.wasabisys.com
```

ここまでで、Mastodonの再起動後からMastodonのメディアは全てwasabiのストレージに保存されます。

## bucketの中身をキャッシュするリバースプロキシを設定

普通オブジェクトストレージを設定すると、転送通信料金がかかる為、節約のためにリバースプロキシでbucketの中身を一部メインサーバーにキャッシュする設定を組み込みます。wasabiの場合転送通信料金が掛からないので、そのまま全部転送、全部bucketから参照でもいいのですが、なんせwasabiのリージョンがアメリカなので、いちいちアメリカと通信していたら結構表示速度が遅くなります。なので、それを防ぐためにMastodonの本サーバーにキャッシュしておきましょう。

設定はMastodon用のnginx設定ファイルを書き換えます。

私の場合、```/etc/nginx/sites-available/```内に.confファイルを置いています。　なお、編集する際はroot権限が必要なのでsudo付けましょう。

参考にしているサイトの```.confファイル```の例を載せます。

```
proxy_cache_path /tmp/nginx_mstdn_media levels=1:2 keys_zone=mastodon_media:100m max_size=1g inactive=24h;

server {
        listen 80;
        listen [::]:80;
        server_name media.mstdn.io;
        return 301 https://media.mstdn.io$request_uri;

        access_log /dev/null;
        error_log /dev/null;
}

server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;
        server_name media.mstdn.io;

        access_log /var/log/nginx/mstdn-media-access.log;
        error_log /var/log/nginx/mstdn-media-error.log;

        # Add your certificate and HTTPS stuff here

        location /mstdn-media/ {
                proxy_cache mastodon_media;
                proxy_cache_revalidate on;
                proxy_buffering on;
                proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
                proxy_cache_background_update on;
                proxy_cache_lock on;
                proxy_cache_valid 1d;
                proxy_cache_valid 404 1h;
                proxy_ignore_headers Cache-Control;
                add_header X-Cached $upstream_cache_status;
                proxy_pass https://s3.wasabisys.com/mstdn-media/;
        }

}
```

```media.mstdn.io``` は自分のドメインに置き換えて、 ```https://s3.wasabisys.com/mstdn-media/``` は、ドメインが ```example.com``` で、bucket名が ```mstdn-media-qiita``` で、westリージョンなら ```https://s3.us-west-1.wasabisys.com/mstdn-media-qiita/``` となります。といった具合に自分で置き換えてください。

置き換え後、 ```sudo nginx -s reload``` でnginxをリロードします。


## wasabiと既存のMastodonのデータ同期

この項目は、Mastodonを新規に立てる場合は不要です。

まず、Mastodonが動作するOSに、aws-cliをインストールします。AWSやAWS互換SaaSと接続する為のコマンドツールです。python製なので、python(3系で大丈夫)を導入した上で、python3-pipをインストールします。

Ubuntu上で動作している(パッケージマネージャがaptの場合)前提で解説します。

```
$ sudo apt install python3
$ sudo apt install python3-pip
```

pythonとpip導入後、pipでawscliをインストール

```
$ pip3 install awscli
```

続いて、

```
$ aws configure
```

をコマンドを入れると、AWS CLIの設定画面になります。

先程wasabiで発行したAccess keyとSecret keyをそれぞれ```Access Key ID```, ```Secret Access Key```で入力、Default Regionはwasabiのbucket一覧にかかれているRegionの項目を入れます。今回の場合だと```us-west-1```、もしeastリージョンの場合は```us-east-1```を入力。```Default output format```の部分は無視します。

では、既存メディアと同期しましょう。Mastodonのディレクトリに移動して、```public/system```以下に入っているファイルを全て転送しましょう。今回の場合は、```{bucket名}```には```mstdn-media-qiita```が入ります。なお、選択したリージョンによってendpointが全く異なる(ここ本当にわかりにくい)ので、注意。

#### us-west-1リージョンの場合
```
$ aws s3 sync public/system s3://{bucket名}/ --endpoint-url=https://s3.us-west-1.wasabisys.com
```

#### us-east-1リージョンの場合
```
$ aws s3 sync public/system s3://{bucket名}/ --endpoint-url=https://s3.wasabisys.com
```

これで、Mastodonメディアフォルダとwasabiとの同期が始まります。

# まとめ

自分自身別にサーバー触れるわけでもなく、しかもwasabiを利用している例は無かったのでかなり苦労しました。やってみてわかったのは日本語でこういった技術情報でまともなものがあると思うなってことですね。日本語の情報はあくまでヒント程度に、基本は英語のドキュメントを読み込んだりグーグル翻訳に頼りながら手順確認するのが一番手っ取り早いです。

また、自分みたいに右も左もわからない人向けに解説したつもりなので、もし分からない事があればコメント下さい。

拙い説明ですから、問題があったり、ここはこうでは？みたいなコメントあったらぜひぜひください。

# 参考サイト

- Moving Mastodon's media files to Wasabi Object Storage 
[https://angristan.xyz/moving-mastodon-media-files-to-wasabi-object-storage/](https://angristan.xyz/moving-mastodon-media-files-to-wasabi-object-storage/)