Cloud9の無料アカウントでMastodonを起動させる

#Mastodon
[Mastodon](https://github.com/tootsuite/mastodon)は、オープンソースの分散型SNSで、技術的にはRailsアプリケーションの一つです。フロンドエンドにはReact + Reduxが使われていたりします。

#Cloud9
[Cloud9](https://c9.io/)は、クラウド型のIDEで、ブラウザ上で動作するのが特徴です。(その気になればスマートフォンからでも扱えます。)
Cloud9のアカウントプランには無料のものがありますので、もちろん制約はありますが無料で様々な開発に使うことができます。

このCloud9ですが、WorkSpaceがほぼ完全なLinux(Debian)になっており、node.jsやApache HTTP serverなど多くのパッケージが最初から入っているため、このIDEで作業しながらデバッグ環境を動かすことができます。
今回は、これを利用してMastodonを稼働させられないかという試みの結果、意外といけると判明したので手順を記しておきます。

Cloud9無料アカウントのWorkSpaceはMemoryが**512MB**、Storageが**2GB**までというMastodonにとっては非常に厳しい環境であるため、動いてもせいぜい開発用か、おひとり様インスタンスにしかならないかと思いますが、それでもという方は以下の手順で建てられます。所要時間は**1時間半**くらいは見ておいたほうがいいと思います。

#手順
###Cloud9アカウントの作成
これはCloud9のサイトから指示に従えば特に問題ないとは思いますが、**クレジットカード情報**が必要です。もちろん有料アカウントにしない限りは一切課金されません。

###WorkSpaceの作成
アカウントを取得してマイページへ行くとこんな感じになっています。![キャプチャ_LI.jpg](https://qiita-image-store.s3.amazonaws.com/0/51289/4caab96f-7fb9-c618-a12b-97bbed1b253a.jpeg)
私のアカウントのものですので既にWorkSpaceができていますが、最初は赤矢印で示したCreateボタンしかないはずです。


Createボタンをクリックすると、以下のようなページに飛ぶので、とりあえずWorkSpace nameに何か入力して、Privateを選択、choose a templateはblankを選択してCreateします。![キャプチャ2.PNG](https://qiita-image-store.s3.amazonaws.com/0/51289/2132a6c4-3368-554b-7cee-b22458016df2.png)

するとしばらく待たされた後にお待ちかねのIDE画面が現れます。![キャプチャ3_LI.jpg](https://qiita-image-store.s3.amazonaws.com/0/51289/1896be6d-3368-c9e2-2f7f-0f9fec9dc466.jpeg)

下側にターミナル、上側にエディタ、左にディレクトリツリーというレイアウトになっています。右上にMEMORY, CPU, DISKと書かれたバーがありますが、まだ3つともほとんど使われていませんね。ここから下部のターミナルを使用して必要なものをたくさん入れていきます。

###必要なパッケージのインストールなど
まず、Cloud9環境はセキュリティ関係の問題の影響（？）でDockerが動かせないので、Non-Dockerで動かします。
必要なパッケージ類の一覧は[オフィシャルのProductionガイド](https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Production-guide.md#dependency-installation)を参考にしました。

####注意
この先、aptを何度か使います。apt **update**は頻繁に行いますが、apt **upgrade**は**絶対に行わないでください。**最初から入っているパッケージ類をupgradeすると、それが最初から入っているものとして扱われなくなるのか、DISKの使用量が一気にかさんでしまいます。

###node.js
すでに入ってるのでパス。```$ node -v```で確認できます。

###yarn
[Productionガイド](https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Production-guide.md#dependency-installation)ではaptで入れることになっていますが、Cloud9環境ではなぜかこいつがインストールできないので、npmから入れます。

```
npm --global install yarn
```


###rootへ切り替え
Cloud9では、rootへの切り替え権限も与えてくれるので、これからしばらくrootで作業します。

```
sudo su -
```

###apt update
apt updateをしたいのですが、デフォルトのままではapt installの時にエラーが起こるので、それを回避します。
まず、原因となるudevを書き換えます。

```
nano /etc/init.d/udev
```
udevを開いたら、`### END INIT INFO`とある行の次の行に、`exit 0`と書き込んで保存します。
その後、以下を実行します。

```
dpkg --configure -a
apt update
```
そうしたら、先ほどの手順でもう一度udevを開き、先ほど書き込んだ`exit 0`を削除して保存します。


###諸々のパッケージ
必要なパッケージが多いので、以下を実行して一気に入れましょう

```
apt -y install imagemagick libpq-dev libxml2-dev libxslt1-dev file git-core g++ libprotobuf-dev protobuf-compiler pkg-config gcc autoconf bison build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm3 libgdbm-dev redis-server redis-tools postgresql postgresql-contrib libidn11-dev libicu-dev
```

###ffmpeg
これが非常にくせ者でした。Debianは「フリーライセンスのものしか提供しない」という方針で、MP3エンコーダなどを含むffmpegは提供していません。deb-multimediaというリポジトリを使用するといいという情報も見つけたのですが、色々試してもどうもapt経由だと`unmet dependencies`が発生しインストールできません。なのでdeb-multimediaから必要なライブラリをインストールしたあと、**仕方なく**ソースコードからビルドします。非常に時間がかかります。

**先に下にある追記をお読みください**

```shell-session:ソースからビルドする場合
echo 'deb http://www.deb-multimedia.org jessie main non-free' >> /etc/apt/sources.list
apt update
apt -y install deb-multimedia-keyring
apt update
apt -y install build-essential libmp3lame-dev libvorbis-dev libtheora-dev libspeex-dev yasm pkg-config libfaac-dev libopenjpeg-dev libx264-dev
mkdir software
cd software
wget http://ffmpeg.org/releases/ffmpeg-3.4.tar.bz2
cd ..
mkdir src
cd src
tar xvjf ../software/ffmpeg-3.4.tar.bz2
cd ffmpeg-3.4
./configure --disable-doc --disable-manpages --disable-ffplay --disable-ffprobe --disable-ffserver --enable-gpl --enable-postproc --enable-swscale --enable-avfilter --enable-libmp3lame --enable-libvorbis --enable-libtheora --enable-libx264 --enable-libspeex --enable-shared --enable-pthreads --enable-libopenjpeg --enable-nonfree
make
make install
/sbin/ldconfig
```
ビルドが終わったら、ソースコード類は**ディスク容量を食うだけ**なので削除します。また、**rootから出ます**。

```
cd
rm -r src/* software/*
rmdir src software
logout
```

>**17/11/20 23:00 追記**
>Static-build版を持ってきて入れるという手がありました。動作確認はしていませんが、ソースからビルドすると平気で30分とか持っていかれるので、こっちのほうがいいのではないかと思います。下記のコマンドでffmpegを入れる場合は上記ソースからビルドするコマンドは一切不要です。インストールしたらrootから出ます。

```shell-session:static-build版を入れる場合
mkdir software
cd software
wget https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-64bit-static.tar.xz
tar Jxfv ffmpeg-release-64bit-static.tar.xz
cp ffmpeg-3.4-64bit-static/ffmpeg /usr/bin/
cd
rm -r software/*
rmdir software
logout
```

###PostgreSQLの設定
PostgreSQLは元から入っているのですが、設定を変更する必要があるのでやっておきます。まずはDBユーザの作成です

```
sudo su - postgres -c 'psql -c "CREATE USER mastodon CREATEDB;"'
```
次に、pg_hba.confを編集します。

```
sudo nano /etc/postgresql/9.3/main/pg_hba.conf
```
ファイル中、`# "local" is for Unix domain socket connections only`の下行`local all all peer`となっているところを、

```
local all all trust
```
と変更します。変更したらサービスを再起動します。ついでにredisも再起動。

```
sudo service postgresql restart
sudo service redis-server restart
```

###必要なnode.jsとRubyのパッケージを取得
いよいよMastodonのソースコードをとってきます。次にCloud9に元から入っているrvmを使ってRuby-2.4.2を入れます。

```
cd ~
git clone https://github.com/tootsuite/mastodon.git live
cd ~/live
git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)
rvm install ruby-2.4.2
```
bundlerとyarnを使って必要なパッケージを入れます。`bundle install`の引数は本番環境の場合のものです。development環境やtest環境で建てる場合は適宜変えてください。今後も本番環境として作業を進めます。

```
gem install bundler
bundle install --deployment --without development test
sudo yarn install --pure-lockfile
```

この辺でDISK容量がかなりやばいはずなので、yarnのキャッシュをクリアします

```
yarn cache clean
```

###Mastodonアプリケーションの設定
アプリケーション設定を行います。

```
cd ~/live
cp .env.production.sample .env.production
nano .env.production
```

編集する項目は以下の通りです。

```
REDIS_HOST=localhost

DB_HOST=/var/run/postgresql
DB_USER=mastodon
DB_NAME=mastodon_production

LOCAL_DOMAIN=[注1]
LOCAL_HTTPS=true

PAPERCLIP_SECRET=[注2]
SECRET_KEY_BASE=[注2]
OTP_SECRET=[注2]

VAPID_PRIVATE_KEY=[注3]
VAPID_PUBLIC_KEY=[注3]
```

[注1]に入力するドメイン名は画像赤丸`Share`をクリックし、`Application:`に書かれているURLからhttps://を取り除いたものになります。また、その右横にあるPublicのチェックボックスにチェックを入れて、外からアクセスできるようにしておきましょう。（Publicにするのは今でなくても大丈夫です。）
![キャプチャ4_LI.jpg](https://qiita-image-store.s3.amazonaws.com/0/51289/09e0d8ca-c07c-370f-e08d-1aa26d6ff6cd.jpeg)

[注2]に入力するのは、ターミナルで`RAILS_ENV=production bundle exec rake secret`を実行して出力された文字列です。なので、これを計3回実行し、得られた3つの文字列をそれぞれの行に貼り付けてください。

[注3]に入力するのは、ターミナルで`RAILS_ENV=production bundle exec rake mastodon:webpush:generate_vapid_key`を実行して得られた`VAPID_PRIVATE_KEY`と`VAPID_PUBLIC_KEY`です。1回実行すると2つの文字列が出力されるので、PRIVATEとPUBLICを間違えずに貼り付けてください。

###データベースのセットアップ
まず、config/database.ymlを編集します。1行、`template: template0`を追加します

```yaml:config/database.yml
default: &default
  adapter: postgresql
  pool: <%= ENV["DB_POOL"] || ENV['MAX_THREADS'] || 5 %>
  timeout: 5000
  encoding: unicode
  template: template0
以下略
```
その後、以下を実行しデータベースをセットアップします

```
RAILS_ENV=production SAFETY_ASSURED=1 bundle exec rails db:setup
```

###CSSとJavaScriptファイルのプリコンパイル
```
RAILS_ENV=production bundle exec rails assets:precompile
```
しばらく時間がかかります。

###Apache HTTP Serverの設定
[Productionガイド](https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Production-guide.md#dependency-installation)ではNginxを使っていますが、Cloud9ではApacheが最初から入っているのでそれを使います。

```
sudo nano /etc/apache2/sites-enabled/001-cloud9.conf
```
内容は以下の通りです。おそらくこのまま使えます。

```
<VirtualHost *:8080>
    DocumentRoot /home/ubuntu/live/public
    ServerName https://${C9_HOSTNAME}:443

    LogLevel info

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

    <Directory /home/ubuntu/live/public>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
    ProxyPreserveHost On
    RequestHeader set X-Forwarded-Proto "https"
    ProxyPass /500.html !
    ProxyPass /sw.js !
    ProxyPass /robots.txt !
    ProxyPass /manifest.json !
    ProxyPass /browserconfig.xml !
    ProxyPass /mask-icon.svg !
    ProxyPassMatch ^(/.*\.(png|ico)$) !
    ProxyPassMatch ^/(assets|avatars|emoji|headers|packs|sounds|system|.well-known/acme-challenge) !

    ProxyPass /api/v1/streaming/ ws://localhost:4000/
    ProxyPassReverse /api/v1/streaming/ ws://localhost:4000/
    ProxyPass / http://localhost:3000/
    ProxyPassReverse / http://localhost:3000/

    ErrorDocument 500 /500.html
    ErrorDocument 501 /500.html
    ErrorDocument 502 /500.html
    ErrorDocument 503 /500.html
    ErrorDocument 504 /500.html
</VirtualHost>

ServerName https://${C9_HOSTNAME}
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
```

また、プロキシとして使うためのいくつかのモジュールを追加します。

```
sudo a2enmod proxy proxy_http proxy_html proxy_wstunnel headers xml2enc
sudo service apache2 restart
```

###サービス起動
いよいよMastodonを起動させます。いくつかのプロセスが同時に動くので、ターミナルのタブの右にある「＋」ボタンから、`New Terminal`を選んで新しいターミナルを3つ開きます。

```shell-session:new_terminal_1
cd ~/live
RAILS_ENV=production PORT=3000 bundle exec puma -C config/puma.rb
```

```shell-session:new_terminal_2
cd ~/live
RAILS_ENV=production DB_POOL=5 bundle exec sidekiq -c 5 -q default -q mailers -q pull -q push
```

```shell-session:new_terminal_3
cd ~/live
NODE_ENV=production PORT=4000 npm run start
```

###HTTPサーバ起動
そして最後にHTTPサーバを起動させてアクセスできるようにします。メニューバーの`Run -> Run With`から`Apache httpd`を選択すると、ターミナルが並んでいるところに新しくタブが追加されて、Apache HTTP Serverが起動します。
![キャプチャ5.PNG](https://qiita-image-store.s3.amazonaws.com/0/51289/a2af61bc-dc15-4b27-6988-bc8582147deb.png)

そしたら、右上のShareボタンをクリックし、`Application:`欄のリンクからサイトへ飛んでみましょう。
![キャプチャ6.PNG](https://qiita-image-store.s3.amazonaws.com/0/51289/d62c47e1-434a-0ce3-745d-b89a781a3a68.png)
うまくいきましたか？

なお、メールサーバの設定を一切していないので、アカウント登録はターミナルに戻って手作業で行うことになります。

###アカウント登録
ターミナルに戻って、以下を実行します。最後の1行は、ユーザを管理者に昇格させるためのコマンドです。
<ユーザID>・<メールアドレス>・<パスワード>はお好きなように書き換えてください。

```
RAILS_ENV=production bundle exec rails c
acc = Account.create!(username: '<ユーザID>')
usr = User.create!(email: '<メールアドレス>', password: '<パスワード>', account: acc)
usr.confirm
acc.save!
usr.save!
exit
RAILS_ENV=production bundle exec rails mastodon:make_admin USERNAME=<ユーザーID>
```
これで、<メールアドレス>・<パスワード>を使ってログインできるようになります。

#まとめ
以上が、Cloud9上でMastodonを建てる~~雑な~~方法です。私が建てた結果では、トゥートはもちろん、リモートフォローや画像の投稿なども問題なくできています。しかし、メモリ使用量は常にギリギリなので、複数ユーザでの運用は厳しいのではないかと思います。

また、コマンドの間違いや「もっといい方法あるよ」(特にffmpeg周り)というのがありましたら是非コメントお願いします。