(My) mastodon インスタンス構築手順

# 最初に
他の環境でどうなるか不明なのと、内容理解せずにほぼコピペだったのでどうしようか迷ったのですが、参考にさせていただいた記事のみでは自分の環境でインスタンスの構築ができなかったので、自分と同じように悩んでる人がいたら、少しでも役に立てばと思いこの手順を公開することにしました。

___※なんか書いてあったらマズイものとかありましたらコッソリ教えてください。。。___
___それと、参考にしたサイトの記事やコマンドをコピーして構築した時の自分用のメモ書きを元にしてるので、権利侵害やルール違反などあるようでしたらそれもコッソリ教えてください。修正します。___

# 環境
### ドメイン
- お名前.com で取得

### サーバ
#### さくらのVPS
- ゾーン：東京第2ゾーン
- CPU：3コア
- メモリ：2GB
- HDD：200GB
- OS：CentOS7

# 構築
## 事前作業

下記の前に、DNSの設定とかあるけど省略。。。

#### パッケージ最新化

```sh
#パッケージアップデートし再起動して反映
$ yum update
$ reboot
```

#### ユーザ追加

```sh
#rootを使わずに、作業用ユーザで作業するためにユーザを追加する。
$ useradd 任意のユーザ名（以下:ユーザ名）
$ passwd ユーザ名
```
#### 追加したユーザの公開鍵配置
作成した作業用ユーザでSSHログインするために、公開鍵を作って配置する。

##### ローカル（自分はMac）で作業
(１度だけ。２回目以降は `~/.ssh` に作られたやつを再利用）

```sh
$ ssh-keygen -t rsa
$ cd ~/.ssh
$ chmod 600 id_rsa.pub
```

```sh
#内容をクリップボードにコピっとく
$ vi id_rsa.pub
```

##### サーバ側で作業

```sh
#ディレクトリ作って、ファイル作ってさっきコピったキーをペーストして保存
$ mkdir -m 700 /home/ユーザ名/.ssh
$ vi /home/ユーザ名/.ssh/authorized_keys
```

```sh
#パーミッションとか変更
$ chmod 600 /home/ユーザ名/.ssh/authorized_keys
$ chown -R ユーザ名:ユーザ名 /home/ユーザ名/.ssh
```

```sh
#作ったユーザでsudoできるように設定
$ visudo
$ usermod -G wheel ユーザ名
$ exit
```

##### ここからは作成したユーザで作業

```sh
#作成したユーザでログイン
$ ssh ユーザ名@サーバのIPアドレス
```

##### rootでのログインを禁止する

```shell-session
$ sudo vi /etc/ssh/sshd_config
```

```shell-session
# PermitRootLoginをnoに変更
#PermitRootLogin yes
PermitRootLogin no
```

```sh
# sshdサービス再起動
$ sudo service sshd restart
```

##### ポート（サービス）穴あけ

```sh
$ sudo firewall-cmd --list-services --zone=public  --permanent
$ sudo firewall-cmd --add-service=http --zone=public --permanent
$ sudo firewall-cmd --add-service=https --zone=public --permanent
$ sudo firewall-cmd --add-port=80/tcp --zone=public --permanent
$ sudo firewall-cmd --add-port=443/tcp --zone=public --permanent
$ sudo firewall-cmd --list-services --zone=public  --permanent
$ sudo firewall-cmd --reload
```
※よくわかってませんが、たぶん `--add-service=https` と `--add-port=443/tcp` は同じことなので、どちらかひとつでいいかも。（よくわからないので自分は両方やってます。）


## Docker
参考にした記事
[Dockerで雑にMastodonを起動する方法](http://qiita.com/zembutsu/items/fd52a504321dd5d6f0b8)
※Dockerについてはホント勉強不足で、どういう仕組で動いてるのか、などまだ理解してません。参考にした上記サイトのコマンドをほぼコピペしてます・・・。これから勉強します！

```sh
$ curl -sSL https://get.docker.com/ | sh
$ sudo systemctl enable docker
$ sudo systemctl start docker
```

```sh
# 次のコマンドでエラーになるので sudo -i しとく
$ sudo -i

$ curl -L https://github.com/docker/compose/releases/download/1.12.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
$ chmod +x /usr/local/bin/docker-compose

# exitしてrootを抜ける
$ exit
```

dockerグループ作成して＄USERを所属させる

```sh
# dockerグループがなければ作る
$ sudo groupadd docker

# 現行ユーザをdockerグループに所属させる
$ sudo gpasswd -a $USER docker
$ sudo usermod -aG docker ユーザ名

# dockerデーモンを再起動する (CentOS7の場合)
$ sudo systemctl restart docker

# exitして再ログインすると反映される。
$ exit
```

___最後の exit 大事！___

以下コマンドで `Server:` があれば成功（としてる）

```sh
$ docker version
Client:
 Version:      17.04.0-ce
 API version:  1.28
 Go version:   go1.7.5
 Git commit:   4845c56
 Built:        Mon Apr  3 18:01:50 2017
 OS/Arch:      linux/amd64

Server:
 Version:      17.04.0-ce
 API version:  1.28 (minimum version 1.12)
 Go version:   go1.7.5
 Git commit:   4845c56
 Built:        Mon Apr  3 18:01:50 2017
 OS/Arch:      linux/amd64
 Experimental: false
```

## nginx
参考にした記事
[CentOS 7 (5, 6) で "安定版 (最新版)" のNginxをインストールする方法](http://qiita.com/noraworld/items/1aae57dcbe428089c7d5)

`/etc/yum.repos.d/nginx.repo` を作って

```sh
$ sudo vi /etc/yum.repos.d/nginx.repo
```

以下を追加

```
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1
```

`--enablerepo=nginx` を付けて `yum install`

```sh
$ sudo yum -y --enablerepo=nginx install nginx

#バージョン確認
$ nginx -v
```
これでnginxインストールは完了

## Let's Encrypt(certbot)
Let's Encryptのクライアントのcertbotをインストール

```ssh
$ wget https://dl.eff.org/certbot-auto
$ sudo chmod a+x certbot-auto
$ ./certbot-auto
```

## mastodon

```ssh
$ git clone https://github.com/tootsuite/mastodon.git
$ cd mastodon/
```
自分はcheckoutしませんでしたが、 `git tag -l` すると、当時の最新は `V1.2.2` でしたので、
以下はV1.2.2利用を想定。

### envファイルの編集 (その１)

```ssh
$ cp .env.production.sample .env.production
$ vi .env.production
```

DB,ドメイン,内部ssl参照用(?)の設定を追記
※内部SSL参照用のってしてるのは、これをコメントアウトしたままだと `Uncaught DOMException` っていうWebSocketのエラーが出るので。

```
DB_USER=任意のDBユーザ名
DB_NAME=任意のDB名
DB_PASS=任意のDBパスワード

LOCAL_DOMAIN=自分のドメイン（例：example.com）

#以下コメントを外す
#LOCAL_HTTPS=true
LOCAL_HTTPS=true
#ここまで編集して一旦保存して編集を抜ける
```

### docker-compose.ymlの編集

```ssh
$ vi docker-compose.yml
```

以下、dbとredisセクションから `volumes:` のコメントを外す

```
  db:
    restart: always
    image: postgres:alpine
### Uncomment to enable DB persistance
    volumes:
      - ./postgres:/var/lib/postgresql/data

  redis:
    restart: always
    image: redis:alpine
### Uncomment to enable REDIS persistance
    volumes:
      - ./redis:/data
```

```sh
$ docker-compose pull

#以下`docker-compose` コマンドを3回実行し、メモに残しておく。
$ docker-compose run --rm web rake secret
$ docker-compose run --rm web rake secret
$ docker-compose run --rm web rake secret
```

### envファイルの編集 (その2)

```ssh
$ vi .env.production
```

上記 `docker-compose run --rm web rake secret` コマンドで取得した３つのキーをそれぞれ上から以下にペースト

```
PAPERCLIP_SECRET=
SECRET_KEY_BASE=
OTP_SECRET=
```

ここでついでにメール(SMTP)も設定
(ドメイン取得したところでDNSのDKIMの設定やAPI払い出しとか忘れずに！)
自分はsparkpostを使ってます

```
SMTP_SERVER=smtp.sparkpostmail.com
SMTP_PORT=587
SMTP_LOGIN=SMTP_Injection
SMTP_PASSWORD=sparkpostで取得したAPIキー
SMTP_FROM_ADDRESS=notifications@ドメイン
#SMTP_DOMAIN= # defaults to LOCAL_DOMAIN
#SMTP_DELIVERY_METHOD=smtp # delivery method can also be sendmail
SMTP_AUTH_METHOD=plain
SMTP_OPENSSL_VERIFY_MODE=none
SMTP_ENABLE_STARTTLS_AUTO=true
```

ビルドする

```sh
$ docker-compose build
```

ここまででdockerの設定終わりかな？

## nginxの設定

```ssh
$ sudo vi /etc/nginx/conf.d/mastodon.conf
```

https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Production-guide.md
ここから設定をコピペして、
example.comを自分のドメインに置き換え。

__最近のをコピペするとassets配下（CSSとか画像とか）が見れない事象が発生するので、以下を対応。__
__（ここが一番ハマったところで、自分の環境だけなのかもわからないし、原因も解ってません。とりあえず自分の場合は以下対応することで解決出来ました。）__

```
#コピペしたmastodon.conf内の以下2行を削除
  # Useful for Let's Encrypt
  location /.well-known/acme-challenge/ { allow all; }
```

## 証明書取得
先程インストールしたcertbotを使って証明書を取得

```ssh
$ ./certbot-auto certonly --standalone -d ドメイン --rsa-key-size 4096
$ sudo openssl dhparam 2048 -out /etc/ssl/certs/dhparam.pem
```
dhparamもいらないのかも？
あってもなくても動いた気がします。。。
ただ、デフォルトのmastodon.confだとdhparamの設定項目があるので、上記をやらないと動かないです。

## 起動していきます
#### nginx

```ssh
$ sudo systemctl enable nginx
$ sudo systemctl start nginx
```

#### docker

```ssh
$ cd mastodon/
$ docker-compose up -d
```

#### DB

```ssh
$ sudo docker exec -it mastodon_db_1 /bin/bash

# デフォルトのpostgresユーザーを使う
su - postgres
createuser -P envファイルで記載した任意のDBユーザ名
createdb 同じく任意のDB名 -O 今作った任意のユーザ名
```

exitしてコンテナから戻ってきたら、次に `db:migrate` と `assets:precompile` をしていく。

```ssh
$ docker-compose run --rm web rails db:migrate
$ docker-compose run --rm web rails assets:precompile

#念のためdockerを再起動
$ docker-compose stop && docker-compose up -d
```

__構築完了！__
と言いたいところですが、サーバー管理者がやるべき作業がもう少しあります。

# 構築後のサーバ設定


### mastodon:daily の設定
※コメントでご指摘頂きました。ありがとうございます。
参考にした記事
[Mastodonのサーバ間通信が切れた場合のリカバリ](http://qiita.com/clworld/items/bc3d8f97d38f2ba58492)

これを設定しないと、 [Mastodon でリモートインスタンスから自分のトゥートがみえなくなることがある](http://cryks.hateblo.jp/entry/2017/04/18/125351)
とのことなので、大切なインスタンス参加者のためにも設定必須です。

```shell-session
#cronに日次バッチを設定(自分は毎日朝5時と11時に設定した)
0 5,11 * * * /bin/bash -l -c 'cd <Mastodonがあるディレクトリ> && docker-compose run --rm web rake mastodon:daily'
```
___追記___
[Mastodon インスタンスのリモートフォローの仕組みと必要な購読更新の設定方法](http://qiita.com/koteitan/items/fadbe900c88481888917)
上記記事参考にCronの実行を１日２回に変更

### Let's encryptの自動更新
参考にした記事
[さくらの VPS + CentOS7 で 俺専用 Mastodon インスタンスを立ててみた話](https://hyper-text.org/archives/2017/04/mastodon-instance-single-user.shtml)

Let's encryptのクライアントcertbotを使って証明書を取得しましたが、Let's encryptの証明書は90日間で有効期限が切れるとのことです。
更新用のコマンド `renew` が用意されているのでそれを cron に登録し、更新作業を自動化します。

```shell-session
#毎週土曜日の06:00に更新し、nginxを再起動
#以下はcertbot-autoがhomeディレクトリ直下にインストールされている場合

0 6 * * 6 sudo systemctl stop nginx && ~/certbot-auto renew && sudo systemctl start nginx
```
有効期限は90日間なので毎週やる必要はないと思いますが、参考にした記事で毎週やってたので右に倣えしました。


# アカウント登録
`https://ドメイン/` にアクセスして自分のアカウントを登録。

# 管理者権限付与

登録した自分のアカウントを以下で管理者権限を付与

```ssh
$ docker exec -it mastodon_web_1 /bin/sh
$ RAILS_ENV=production bundle exec rails mastodon:make_admin USERNAME=登録ユーザー名
```

__以上で完了__


# 謝辞
ここまでくるのに様々なサイトを参考にさせていただきました。
[CentOS初期セットアップ〜アカウント追加・SSH設定・sudo権限](http://qiita.com/ikenyal/items/9abd7b41a68cf62ac424)
[CentOS7でmastodonを建てる](http://qiita.com/motiakoron/items/1e5b0679f7283bfee70b)
[CentOS 7 (5, 6) で "安定版 (最新版)" のNginxをインストールする方法](http://qiita.com/noraworld/items/1aae57dcbe428089c7d5)
[Dockerで雑にMastodonを起動する方法](http://qiita.com/zembutsu/items/fd52a504321dd5d6f0b8)
[Mastodonのサーバ間通信が切れた場合のリカバリ](http://qiita.com/clworld/items/bc3d8f97d38f2ba58492)
上記以外にも、ググってヒットするページはとりあえず読み漁りました。

また、mastodon上で `YOUさん` (https://pawoo.net/@sha1) には深夜遅くまで献身的にアドバイスして頂き、心強かったし大変助かりました。
YOUさんいなかったら途中で諦めてました。。。

__みなさんありがとうございました！__

# 最後に、上記手順で構築したインスタンス
[mbstdn.tokyo (スマホ写真・スマホ写真家・趣味のスマホ写真)](https://mbstdn.tokyo/ "スマホで撮った写真や、スマホフォトグラファーが集う場。 スナップ、ストリートフォト、ポートレート、静物、スマホで撮った写真ならジャンル問いません。")
お気軽にご参加ください。