サーバ、インフラ経験ゼロの初心者がAWSで「【非公式】Unity JP Mastodon」を作ってみた

[Mastodon Advent Calendar 2017](https://qiita.com/advent-calendar/2017/mastodon) 3日目の記事になります。

[【非公式】Unity JP Mastodon](https://unityjp-mastodon.tokyo/)の管理人、荻野です。
![logo.svg](https://unityjp-mastodon.tokyo/packs/logo_full-ea4b24883aebb87285d89fa7358ce38d.svg)

今回はサーバー、インフラの実装経験ゼロの超初心者が、ネットに掲載されている情報のみで生まれて初めて触ったAWSを利用して、Mastodonインスタンスを組み立てたことを書いていきます。

サーバー、インフラ初心者故に引っかかった苦労点や、AWSに全く詳しくなかったために頭から地雷にダイブするなど、バカバカしいお話でも書いていきたいと思います。

ソースだけ読みたい方は[こちら](https://github.com/YuukiOgino/mastodon/tree/unityjpmastodon_v1.6.1)から見れます。

# Mastodonインスタンスを立てる上で参考にさせていただいたサイト

一番お世話になったのが以下のサイトです。インスタンス作成時は、これをそのまま使わせていただきました。

[マストドンAWS構築チュートリアル完全版|初心者から大規模運用まで](http://webfood.info/mastodon-aws-tutorial/#lets-encryptcron)

簡単な自動メンテナンス処理も記載されているのが本当にありがたかったです。
5月のゴールデンウィークに当時v1.3.2だったMastodonインスタンスを立てたのですが、ほぼこのサイトに書いてある手順をほぼそのままなぞったらMastodonインスタンスがAWSで動きました。

※現状のv2.0以上だと、一部ソフトウェアのバージョンをアップしないとビルドが通らないことがあります

他に参考にさせていただいたサイトをいくつか掲載します
[AWSの無料SSLを使ってmastodonインスタンスを立てる手順](https://qiita.com/genya0407/items/afb9c3f075225de856ed)
[AWSでMastodonサーバー立てました chitose.moe](https://qiita.com/kawax/items/5307b58e549dd9cc3928)
[AWSのEC2で最小限の努力でmastodonを構築する](https://qiita.com/tsuitta_dayo/items/dfd659ec68435653d16a)
[マストドンのインスタンスを構築するドン]
(https://gnzo.com/labo/archives/484)
[Mastodon インスタンスを運用しているサーバを HTTP/2 対応させた話 （CentOS7 + nginx + OpenSSL）](https://hyper-text.org/archives/2017/04/mastodon_instance_http2_enable.shtml)

# AWS設定

Mastodonインスタンスを立てるにあたり、使用したAWSサービスは以下の通りです。

・EC2インスタンス
OS：ubuntu16.04
タイプ：t2.micro

インスタンス作成時のタイプ:t2.medium
※t2.microだとアセットの初回ビルドでメモリの上限を超えて落ちるため

・RDS
エンジン：PostgreSQL
クラス：db.t2.micro
ストレージ：20GB

・ElastiChache
タイプ：cache.t2.micro

・VPC
・S3
・CloudWatch
・CloudFront
・Route 53
・Certificate Manager

※ほぼ全て無料枠に抑えています。

無料枠でおさめられれば、費用はだいたい１００円以下となっています。
画像をのぞいて、Unityリンク集やお知らせ表示の簡単なカスタマイズを入れています。

![スクリーンショット 2017-12-02 21.25.28.png](https://qiita-image-store.s3.amazonaws.com/0/104377/f0569fd5-88b3-98a9-6fe8-ead62135388b.png)

# 現バージョン(v2.0以上)でMastodonインスタンスをAWSで動かしたい場合

Mastodonは日々高速で改良が加えられているため、２０１７年4月前に記載された[マストドンAWS構築チュートリアル完全版](http://webfood.info/mastodon-aws-tutorial/#lets-encryptcron)を見て新規にMastodonインスタンスを組み立てる場合、いくつか引っかかる点と当時未実装だった機能があります。

## dockerのバージョンが1.13以上であることが必須

v1.4.1からdockerが1.13以上でないと、ビルドが通らないように変更されています。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">現在、非公式のUnity Mastodonのバージョンアップ中<br>どうやら1.4.1はdockerが1.13以上でないとビルドできないようになっているっぽいな</p>&mdash; 荻野雄季@デジゲー博X-03ab (@YuukiOgino) <a href="https://twitter.com/YuukiOgino/status/875018664570834945?ref_src=twsrc%5Etfw">2017年6月14日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

バージョンが1.１３より低い場合、[公式ドキュメント](https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/#set-up-the-repository)を見て、docker ceをインストールしましょう。

## プッシュ通知（VAPIDキー）

プッシュ通知はv1.5.0から新規に追加されました。
そのため、プッシュ通知に対応する場合は以下の作業が追加されます。

１.以下のコマンドを叩いて秘密鍵/変数を生成します
RAILS_ENV=production bundle exec rake mastodon:webpush:generate_vapid_key
（ドッカーの場合、docker-compose run --rm web rake mastodon:webpush:generate_vapid_key）

2.生成した秘密鍵/変数を設定ファイルにセット
大抵の人が.env.productionと名付けるファイルで、以下の定数に生成した秘密鍵と変数をセットします。

```
VAPID_PRIVATE_KEY =
VAPID_PUBLIC_KEY =
```

生成さえすれば、どちらがどのKEYに対応しているかはわかると思います。

# AWS(インフラ)初心者ゆえやらかした失敗

AWSは２017年５月のGWで初めて触ったため、いくつかバカバカしい失敗をしました。
自分への戒めとして、晒していきます。

## RDSとElastiCacheを本番稼動用のデフォルト設定のまま本番公開した

はい、Mastodonインスタンス作成時に初めてAWSに触ったため、ろくに調べずに無知故にやらかした失敗です。

これ、何が失敗かというと、最大でも一日あたりのアクティブユーザーが50人以下のコンテンツなのに、明らかに超オーバースペックな上に壮大に無駄な費用が発生するモンスタースペックな構成に知らず知らずにしてしまったことです。

１.ElastiCache
ElastiCacheのデフォルトだとシミュレーションができなかったので、大雑把な計算をしてみました。

ノードのタイプ：cache.r4.large（メモリ12.3GB）　時間で$0.288の費用発生
レプリケーション数：２

大雑把に料金を計算すると$0.288×２×24×31=$428.544(約48,083円）
明らかに不必要な投資です。

2.RDS
こちらは実際のデフォルト設定からある程度シミュレーションで計算ができました。
![スクリーンショット 2017-12-02 19.07.27.png](https://qiita-image-store.s3.amazonaws.com/0/104377/035564fd-ee95-4bec-f3fb-014c2a503aab.png)

なんと驚愕の月額$1386.07(約155,521円)！
明らかに過剰投資です。

これは現在の料金設定からの計算であり、当時は１日１万ずつ自動課金されるぐらいの消費をしていました。
構築時は設定した時間が３〜４時間程度な上、請求の欄を見ていなかったために異常な料金の上がり方に気づいていませんでした。

リリースしてから１日後、請求額を見たら明らかに想定と違う料金の上がり方をしていることに気づき、料金を調査して発覚しました。これをどうにかしないと毎月２０万消える恐ろしいモノになるため、早期に構成を変更せざるを得ませんでした。

この時に初めてAWSの仕様として、**容量は簡単に上げることは可能だが、容量を<font color="0xff0000">減らすことはできない**ことを知り、改めてインスタンスを作り直さないといけないことになりました。

### ElastiCacheの再設定

Mastodonはサーバーキャッシュは全て捨てても、直近で影響が出るのがホームのページの表示ぐらいというのが検証してわかったため、完全に付け替える方針にしました。
超小規模であればレプリケーション数は１、メモリ0.5GBでも十分と判断し、ElastiCacheは無料枠に収めるインスタンスを改めて作成し、付け替えました。

無事に接続を確認後、金食い虫のインスタンスは即刻削除して料金を発生しないようにしました。

### RDSの再設定

一番困ったのがDB、RDSの再構築です。一度世間に解放してしまった以上、当時９０人弱のユーザー登録があったので破棄してしまうと再度登録させるという非常に面倒な手間を強いることになるため、DBをそのまま移植しないといけません。

仕事では基本的にSQLでの流し込みぐらいしかしてなかったため、時間が過ぎるごとに課金額があがる恐怖と戦いながらネット上でRDSのバックアップと復旧方法を検索しました。

最終的に以下の方法でDBの移植を行いました。

1.dumpファイル作成

まずdumpファイルを作成します。叩いたコマンドは以下の通りです。

```
psql -f [作成するdumpファイル名] --host=[RDSエンドポイント]  --port=[ポート] --username=[ユーザー名] --password --dbname=[DB名]
```

2.dumpから復旧

無料枠で収まるRDSインスタンスを作成後、以下のコマンドを実行しました。

```
sudo pg_restore -c -h [RDSエンドポイント] -U [ユーザ名] -d [DB名] [dumpファイル] 
```

詳しくは[PostgreSQL 9.2.4文書](https://www.postgresql.jp/document/9.2/html/app-pgrestore.html)をご覧ください。

あとは新規に作成したRDSに接続するように設定を変更し、無事トゥート一覧やユーザーリストが表示されていることを確認後、古いインスタンスを即時削除しました。

これでなんとかDBの復旧ができました。
頭ではDBはバックアップとって復旧する、ということをやらなければいけないとはわかってましたが、dumpファイルからの復旧は初めての作業だったため、非常にテンパった覚えがあります。

久しぶりに頭をフル回転させましたw

## S３をダイレクトに接続していた結果、通信プロトコルがHTTP1.1形式でページの表示が遅かった

これもやらかしの一つです。ドキュメントを読めば明らかなのですが、S3の通信プロトコルはHTTP/1.1のため、せっかくHTTPSで接続しているのにHTTP/2.0にしていないために非常に無駄な通信コストが発生していました。

CloudFrontを経由すればS3でもHTTP/2.0対応ができることを知ったため、早速試してみました。

1.ドメイン＆証明書発行

S３用のドメインと証明書を発行する必要があるため、AWSの証明書で作成します。
mastodonインスタンス作成時と同様、証明書のリクエストを行います。このドメインさえ確保できれば、あとはCloudFrontでインスタンスを作成するのみです。
![スクリーンショット 2017-12-02 20.41.29.png](https://qiita-image-store.s3.amazonaws.com/0/104377/d4a479d6-be22-b125-9b6c-2b7e8a282957.png)

2.CloudFrontインスタンス作成

まずインスタンスを作成します。上のWebから作成します。
![スクリーンショット 2017-12-02 20.34.50.png](https://qiita-image-store.s3.amazonaws.com/0/104377/3853742e-6d3b-b95d-b35b-a341c77019d3.png)

Create Distribution画面が出てくるので、Origin Domain NameにS３のバケットをセットします。

![スクリーンショット 2017-12-02 20.35.23.png](https://qiita-image-store.s3.amazonaws.com/0/104377/808899c8-bd5b-0e81-874a-70498c1fceff.png)

続いて、SSL CertificateでCustom SSL Certificateを選択し、先ほど発行したドメインをセットします。

![スクリーンショット 2017-12-02 20.36.40.png](https://qiita-image-store.s3.amazonaws.com/0/104377/7d264355-0195-abad-6c56-48aa1b64cc20.png)

最後、HTTP VersionsがHTTP/2をサポートする設定になってるか確認し、インスタンスを作成します。
![スクリーンショット 2017-12-02 20.35.59.png](https://qiita-image-store.s3.amazonaws.com/0/104377/a718d366-03d4-842d-237d-9d873438f070.png)

最後、このドメインをS3_BUCKETに設定すれば、HTTP/2.0対応完了となります。
HTTP/2.0に変更後、画像等のアセットダウンロードが体感速度的に２倍ぐらい早くなった気がします。

参考に、画像がたくさん上がってくるPawooのインスタンスユーザーを表示した上での速度です。

![スクリーンショット 2017-12-02 20.58.30.png](https://qiita-image-store.s3.amazonaws.com/0/104377/c23195e4-d8b6-6025-ce4e-71d8396a54f5.png)

※すみません、データ取る前に切り替えてしまったので、変更前の具体的な数値が出せないです

３３の画像を読み込んだ上での速度です

一見わかりにくくて申し訳ないですが、これはAWSで全て無料枠で収めてこの速度が出るということなので、EC2やElastiCacheの性能をあげればもっと早くなると思います。

# Mastodonインスタンスを組み立てる上で役だったスキル

私は一応、会社で某ソーシャルゲームのWebフロントエンジニアのため、会社で（嫌でも）以下の経験をしたのがMastodonを立てる時に役立ちました。

・簡単なLinuxコマンドとコマンドライン

大体本番で使われているWebサーバーはLinuxのCUIベースだったので、フロントのソースをアップするために何回かviを編集していたこと、シンクコマンドを叩いていたのが役に立ちました。（GUIばっかり触ってると、CUIだとわかりにくい部分があるため）
Linuxでサーバーを立てる場合、ある程度Linuxコマンドを叩いて慣れておいたほうがいいと思います。

# MastodonとAWSを触ったり、地雷を踏んだりして得られたスキル

最後のまとめです。
インスタンス作成時はAWSを触って４日、色々と失敗をやらかして得られた経験は以下の通りです。

・RDS（PostgreSQL）でのバックアップ復旧作業
・AWSにおけるサーバー環境構築
・Mastodonインスタンス構築の知見
・サーバーコストへの意識
・ユーザーがいる状況での本番環境のバージョンを更新するという恐怖と覚悟

とくによかったと思えるのはサーバーコストへの意識です。
実際に立てたからわかることですが、サーバーコストを適切にしないと無駄な費用が発生して回らなくなるというのをよく理解しました。
実質、フロント部分しか触ってないと、会社環境によってはこの辺りの意識がないところもあるので、改めてサーバーコストの意識が高まったのはやってよかったと思います。

本番環境の更新は毎回冷や汗を書きます。なぜなら会社では万が一が起きても頼れる人がいますが、このインスタンスで頼れるのは自分一人です。万が一が発生した場合、ネット上で情報がなければお手上げです。
謎のエラーでバージョンが更新できずに起動できない（だいたいコンフリクト放置が原因）ときは本当にあせります。

かなり必死で頭を回してるからこそ、動いた時に得られる経験値というのは相当なものだと感じています。
もし、Web系の会社に行きたいと考えている人は、mastodonインスタンスを立てて運営してみると、色々と実践的な経験を短期間で詰めるかもしれません。

明日はxserverさんによる「インスタンス運用アンチパターン」です。楽しみです！！