Mastodon インスタンスの画像や動画の保存先をクラウドストレージ (Amazon S3) に移行した話

Mastodon インスタンスが取得する画像や動画の保存先を外部サーバに変更して自分のサーバのストレージ消費を抑えた話。Mastodon がデフォルトで対応している Amazon S3 に画像や動画が保存されるように設定した際の手順をまとめます。

日本で話題になってから 1週間も経たないうちに一部では大盛り上がりの Mastodon (マストドン)。

私も先週末に早速いじってみて、さくらの VPS に自分専用 Mastodon (マストドン) インスタンスを立てた話をこの Blog で書きました。

Mastodon インスタンス立ててみてちょっと気になっていたのが、Mastodon はインスタンスに登録されているユーザーがアップロードした画像や動画ファイルはもちろん、連合タイムライン等で表示した画像 (ユーザーごとのアイコンとか含め) や動画まで、すべてそのインスタンスが稼働しているサーバに保存する点です。

私のように自分専用のシングルユーザーインスタンスで運用していたとしても、沢山の人をフォローしたりされたり、接続するインスタンスが増えたりすれば、サーバに保存される画像や動画は結構な量とサイズになります。

そこで、運用を始めてしまってからでちょっと面倒ではあるのですが、画像や動画の保存先を Amazon のクラウドストレージサービスである、Amazon S3 に変更してみたので手順をまとめます。

Mastodon で Amazon S3 を利用する

Mastodon はデフォルトで Amazon S3 に対応していますので、基本的には Amazon S3 の利用開始手続きをして、画像や動画ファイルを置く場所さえきちんと設定してあげれば、あとは Mastodon の設定ファイルに必要な情報を記述するだけで終わります。なのでとっても簡単。

ということで、まずは Amazon Web Service へのアカウント開設など、利用開始に必要な手続きを追えたら、「Amazon S3 のコンソール」 に移動し、データを保存するためのバケットを作成します。

バケットの新規作成

「バケットを作成する」 ボタンを押して、新規バケットの作成ウィザードを立ち上げましょう。

バケットの新規作成 - Amazon S3

バケット名やリージョンを設定します。バケット名については任意ですが、今回はわかりやすいようにインスタンスのドメインを設定しました。リージョンは 「アジアパシフィック(東京)」 を選択。次へ進みます。

新規作成するバケットの名前やリージョンを選択 - Amazon S3

プロパティの設定はとりあえずデフォルトのままで大丈夫なので飛ばします。「次へ」 を押しましょう。

新規作成するバケットのプロパティを設定 - Amazon S3

次の 「アクセス許可の設定」 についても、デフォルトで問題ないのでそのまま 「次へ」 を押せば、バケットの作成が完了します。

新規作成するバケットのアクセス許可を設定 - Amazon S3

IAM でユーザーを追加

次に、「IAM (Identity and Access Management) のコンソール」 に移動します (左上のサービス一覧から選択すれば移動できます)。

IAM (Identity and Access Management) コンソール

「IAM リソース」 の部分にある 「ユーザー」 をクリックすると 「ユーザーを追加」 というボタンがありますので、そちらを押して新規ユーザーの追加画面に進みます。

ユーザー名を任意で入力し、アクセスの種類で 「プログラムによるアクセス」 にチェックを入れて、次のステップに進みましょう。

IAM にユーザーを新規追加

次の画面で、「既存のポリシーを直接アタッチ」 を選択し、下に表示される既存ポリシーの一覧から 「AmazonS3FullAccess」 にチェックを入れて、次のステップに進みます。

既存のポリシーを直接アタッチ

ユーザーの追加が完了すると、下記のように 「アクセスキー ID」 と 「シークレットアクセスキー」 が表示されますので、両方とも確実に控えて IAM での設定は完了です。

ユーザーの追加が完了。「アクセスキー ID」 と 「シークレットアクセスキー」 が表示された例

バケットのアクセス権限を設定

先ほど Amazon S3 に作成したバケットにアクセス権を設定します。今回はバケットに保存した画像などのデータに誰でもアクセスできないと困るので、そのようにポリシーを設定します。

AWS Policy Generator というツールが用意されていますので、それを利用します。下記からアクセスしましょう。

AWS Policy Generator で Amazon S3 用のポリシーを生成

まず、「Select Type of Policy」 で、「S3 Bucket Policy」 を選択します。

それぞれの項目は下記のように入力していきましょう。

  • Effect: Allow
  • Principal: *
  • AWS Service: Amazon S3
  • Actions: s3:GetObject
  • ARN: arn:aws:s3:::[your_bucket_name]/*

「Add Statement」 を押すと設定した内容の確認が表示され、「Generate Policy」 というボタンが表示されますので、それを押せば、下記のような JSON が取得できます。コピーしておきましょう。

{
    "Version": "2012-10-17",
    "Id": "Policy**********",
    "Statement": [
        {
            "Sid": "Stmt**********",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::[your_bucket_name]/*"
        }
    ]
}

ここまできたら、Amazon S3 のコンソールに戻り、バケットの管理画面から、「アクセス権限」 タブへと進み、「バケットポリシー」 を選択すると、入力欄がありますので、先ほどコピーした JSON をペーストして、「保存」 を押します。

バケットポリシーを使用してアクセス権限を設定

特にエラーが出なければ権限設定はこれで完了です。

.env.production の編集

次に Mastodon の設定ファイルを変更し、先ほど作成した Amazon S3 のバケットに画像などが保存されるようにします。

vim .env.production

設定ファイル内には下記の項目がありますので、コメントアウトを外し、必要な値を記述していきます。

S3_ENABLED=true
S3_BUCKET=[バケット名]
AWS_ACCESS_KEY_ID=[アクセスキー]
AWS_SECRET_ACCESS_KEY=[シークレットアクセスキー]
S3_REGION=[リージョン]
S3_PROTOCOL=https
S3_ENDPOINT=https://[リージョン].amazonaws.com

まず、[バケット名][アクセスキー][シークレットアクセスキー] については、先ほど Amazon S3 で設定、取得した内容をそのまま書き込めば OK。

[リージョン] となっている部分ですが、下記のページを参考にします。

例えば、今回私は 「アジアパシフィック(東京)」 リージョンを選択しましたが、上記ページの表で 「Asia Pacific (Tokyo)」 を見てみると、Region、および Endpoint の情報が書かれています。

つまり、東京リージョンであれば、設定ファイルの記述は下記のようになります。

S3_REGION=ap-northeast-1
S3_ENDPOINT=s3-ap-northeast-1.amazonaws.com

ビルドして設定を反映

すでに Mastodon インスタンスが稼働している前提ですが、Mastodon を再ビルドして docker-compose を立ち上げれば、以降、画像や動画はすべて Amazon S3 に保存されるようになります。

# docker-compose stop
# docker-compose build
# docker-compose up -d
# docker-compose run --rm web rails db:migrate
# docker-compose run --rm web rails assets:precompile
# docker stop $(docker ps -a -q) && docker-compose up -d
# systemctl restart nginx

稼働中のインスタンスで Amazon S3 に移行した際の問題

Mastodon インスタンスの新規立ち上げ時に上記の設定をしていれば全く問題ないのですが、私のように一旦稼働して少し時間が経った Mastodon インスタンスで、途中から保存先を変えると、結構面倒なことになります。

というのは、Amazon S3 に画像や動画を保存するように設定したと同時に、すべての画像、動画が Amazon S3 のバケットから読み込まれるように HTML 内のパスが変更されますが、Mastodon は過去に取得した画像を再取得したりといった気の利いたことを一切してくれないので、切り替え前に取得して、自分のサーバに保存されていた画像や動画 (Amazon S3 上には保存されていない) はすべてリンク切れの状態になってしまいます。

例えば、自分が投稿した画像や動画はもちろん、タイムライン上に表示される他のユーザーのアイコンや投稿画像、通知欄のアイコン、あるいは自分のアカウントページに表示される、フォローしている人、フォローされている人の一覧に表示されるアイコンなど、個々のユーザーに紐付いている画像や動画がほぼ全滅します。

ということで、ひと手間余計なのですが、自分のサーバに保存されている画像や動画データを救出して、Amazon S3 に移動してあげないといけません。

Amazon S3 移行前にサーバに保存されたデータの救出

で、肝心の画像データなどがどこにあるかですが、mastodon_web_1 内の /mastodon/public/system 以下に保存されています。

ですので、下記のようにして一旦普通にアクセスできる場所にデータをコピーしてきましょう (Mastodon が /opt/mastodon 以下で稼働している前提です)。

# mkdir /opt/mastodon_backup
# cd /opt/mastodon
# docker cp mastodon_web_1:/mastodon/public/system /opt/mastodon_backup/web

これで、/opt/mastodon_backup/web 以下に、画像と動画ファイル一式がコピーされます。あとは、

# tar zcvf mastodon_web.tar.gz /opt/mastodon_backup/web

などとして、ローカルに落としてくれば救出完了です。バックアップしたファイルのディレクトリ構成は概ね下記のようになっています。

├ accounts
   ├ avatars
   └ headers
├ media_attachments
   └ files
└ preview_cards
   └ images

実際にはさらに階層があって、そこに画像データなどが入っていますが、名前からなんとなく想像がつくとおり、accounts ディレクトリ内にユーザーのアイコンやプロフィールページに設定したヘッダ画像などが保存されています。media_attachments ディレクトリが、トゥートした画像や動画ですね。

あとは、Amazon S3 のバケット内に、ディレクトリ構成が変わらないようにアップロードしてあげればいいだけですので、データの救出さえできればそれ程大変ではありませんが、画像の点数が多いととても面倒。

私の場合は自分専用インスタンスですので、それ程苦労せず移行しましたが (バックアップした画像データのサイズ的には 130MB 程度でした)、公開されていて、ユーザー数がある程度いる Mastodon インスタンスだと恐らく途中からの移行は難しいと思います。やるならインスタンスの立ち上げ時にきちんと設定しておいた方がよいと思いますよ。

関連エントリー