さくらの VPS + CentOS7 で 俺専用 Mastodon インスタンスを立ててみた話

Mastodon インスタンスを自分専用に運用してみようと思い、手元で余っていた さくらの VPS (さくらインターネット) を利用して CentOS7 + nginx + Docker で立ててみたのでメモ

Mastodon (マストドン) が先週の頭、4月10日くらいから日本でも急激に話題になって、@nullkal 氏が自腹で mstdn.jp インスタンスを立ててくれた辺りからはもう一部でお祭り騒ぎになっていました。

で、いい機会だし、ちょっとお勉強を兼ねて自分専用の Mastodon インスタンスを立ててみようと週末に思い立ち、土曜日の空いた時間でやってみたら 2~3時間で比較的簡単に立てられましたので、備忘録がてらエントリーにしてみようと思います。

使用した環境としては下記のような基本構成に、適時必要なものをいくつか入れた感じ。サーバは元々テストサーバとして使っていたやつが用済みになったので流用。なので個人専用インスタンス立てるだけならもっとコスト抑える方法はあると思います。

  • さくらの VPS (2G プラン / SSD50GB)
  • CentOS 7 x86_64 カスタム OS インストール
  • nginx
  • Docker (docker-engine / docker-compose)

Mastodon について

Mastodon

Mastodon とは? については他に色々書かれているので今さら書く必要もなさそう。Mastodon の設計思想自体は特に目新しいものではなく、同じく OStatus に準拠した GNU Social の互換実装なわけですが、リリースされたタイミングやインターフェースを含めたデザインのおかげでしょうか? 一気に人気になりました。

ちなみに日本語で Mastodon を紹介した記事だと下記の記事などが最初ですかね。

あと、日本語で用語などを解説する Wiki も立ち上がっているようです。

Mastodon や GNU Social の思想はともかく、mstdn.jp のように数千どころか数万人のアカウントを抱えてしまうとさすがにそのインフラコストは個人が抱えられる範囲を軽く超えてしまいます。

なので安易にインスタンス立てると多分大変なことになるので、ある程度覚悟のある人以外はやめた方がいいと思いますが、完全に個人専用なら自分の責任の範囲だけで運用できますし、フォロー / フォロワー間でのやりとりに限定すれば完全個人インスタンスで十分楽しめますから、遊びとして試してみるのもいいと思います。

また、他人が作ったインスタンスの運営方針が気に入らないとか、重たくて嫌だとか、あるいは信用できない...... みたいな人にもいいですね。これが本来の設計思想に合致したインスタンスの立て方だとは思いますけども。

さくらの VPS 上に Mastodon インスタンスを立てる

では下記に私がやった手順をまとめていきます。VPS の立ち上げから基本的な設定までは簡単にしか書いていませんが、その辺は一般的な手順として見てください。

CentOS7 の基本設定

まずはまっさらなさくらの VPS に、カスタム OS として用意されている CentOS 7 x86_64 を標準構成でインストールして起動。それから DNS の設定を済ませて、今回のインスタンスで使うドメインでサーバの IP アドレスが名前解決できるようにしておきます。

サーバが立ち上がったら SSH して必要なユーザーを作成後、ファイアウォールの設定。firewall-cmd で必要なポート設定などをしておきます。私の環境では HTTP/HTTPS と SSH 用のポート (初期設定からポート変更) だけ開放。

続いて、

# vi /etc/ssh/sshd_config 

して、SSH 関連の設定を色々。セキュリティ的に問題ないように。

設定が終わったら、

# systemctl restart sshd.service

した上で、SSH しなおしてみて問題ないことを確認。

念のためサーバ時刻周りの設定 (Chrony) を確認。それから基本的なツールをとりあえず入れておきます。

# yum -y install wget
# yum -y groupinstall base
# yum -y install zlib-devel

仕上げに yum update しておきます。

# yum update

あとで入れる Docker がよきに計らってくれるから必要ないとは思いますが、Mastodon のビルド中に Warning が出て気持ち悪かったので下記も自分でインストールしました。

# yum -y install rubygems
# gem -y install bundler
# yum -y install yarn

最後に SELinux を無効化しておきます。

# vi /etc/sysconfig/selinux
SELINUX=disabled

nginx のインストールと設定

次に nginx をインストールします。nginx リポジトリをインストールしてから、nginx 本体をインストールします。

# yum install http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
# yum -y install --enablerepo=nginx nginx
# systemctl start nginx
# systemctl enable nginx

これで私の環境では nginx/1.11.13 がインストールされました。

インストール後に nginx を起動して問題なければひとまずは OK。細かい設定は後でやるので一旦忘れて、Docker 関連のセットアップへ。

Docker のインストールと設定

続いて Docker をインストールしていきます。まずは docker-engine から。

docker-engine のインストール

リポジトリを追加。

# vim /etc/yum.repos.d/docker.repo
[dockerrepo]
name=Docker Repository
baseurl=https://yum.dockerproject.org/repo/main/centos/$releasever/
enabled=1
gpgcheck=1
gpgkey=https://yum.dockerproject.org/gpg

インストールします。

# yum install -y docker-engine

インストールが完了したら起動。

# systemctl start docker
# systemctl enable docker

docker-compose のインストール

次に docker-compose を入れていきます。まずは Changelog を見て、最新のリリースを確認しておきます。

私が作業した時点での最新は 1.12.0 だったので、下記のように任意の場所で最新のリリースを取得。

# curl -L "https://github.com/docker/compose/releases/download/1.12.0/docker-compose-$(uname -s)-$(uname -m)" > /usr/bin/docker-compose

権限を付与します。

# chmod +x /usr/bin/docker-compose

バージョンを問い合わせて、正しくインストールされたことを確認します。

# docker-compose --version
docker-compose version 1.12.0, build b31ff33

docker-compose を落としてもデータがぶっ飛ばないように設定

このままだと、docker-compose を落としたときなどに DB 含めデータが全部ぶっ飛びますので、docker-compose.yml を編集してデータが保存されるようにしておきます。

# vim docker-compose.yml

下記のように設定。

services:
 
  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

これで、データが残るようになります。

Mastodon のインストールと設定

さて、いよいよ Mastodon を入れていきます。今回は、/opt/mastodon に必要なファイルを置く前提で進めます。まずは必要なファイルを GitHub から取得します。

# cd /opt
# git clone https://github.com/tootsuite/mastodon.git
# cd mastodon

以降は、/opt/mastodon 内で作業します。

まず、設定ファイルに記述する、

PAPERCLIP_SECRET=
SECRET_KEY_BASE=
OTP_SECRET=

の各 Key を取得するため、下記のコマンドを 3回実行。1回目は時間かかると思いますが、2回目以降はわりとすぐ終わります。

# docker-compose run --rm web rake secret

処理が終わると、最後に Key が出力されますのでそれをコピーしておきます。前述の通り、3つの Key が必要です。

設定ファイル .env.production の編集

次に設定ファイルを書き換えていきます。

# cp .env.production.sample .env.production
# vim .env.production
DB 関連、ドメイン関連の設定

まずは基本的な設定ですね。

# Service dependencies
REDIS_HOST=redis
REDIS_PORT=6379
DB_HOST=db
DB_USER=example
DB_NAME=example
DB_PASS=************
DB_PORT=5432
 
# Federation
LOCAL_DOMAIN=mastodon.burnworks.com
LOCAL_HTTPS=true

DB に関連する設定を下記に。任意のユーザー名、DB 名、パスワードを設定しますが、後で実際に DB に設定しないといけないので手元で参照できるようにしておきましょう。

DB_USER=example
DB_NAME=example
DB_PASS=************

下記の部分は、ドメイン名の設定と、SSL を有効にする設定。SSL 証明書に関しては後で Let's Encrypt を使用して行います。

# Federation
LOCAL_DOMAIN=mastodon.example.com
LOCAL_HTTPS=true
rake secret key の設定

次に、先ほど rake secret で取得した Key を下記の項目にそれぞれ記述します。

PAPERCLIP_SECRET=
SECRET_KEY_BASE=
OTP_SECRET=
メール関連の設定

メール設定 (E-mail configuration) は、自分専用インスタンスとして利用するなら不要ですが、一応、通知関連で自分宛にメールを飛ばしたい時に必要かなと思ってやっておきました。外部サービスとして、「SparkPost」 を利用する前提です。

まず、SparkPost でアカウントを作成しておきます。

アカウント作成が完了すると、ドメインを登録しろといわれるので登録します。この際、API Key が発行されますので、これを間違いなく手元にメモしておきます。これ忘れると API Key を発行しなおさないといけなくなります。

登録が完了したら、管理画面からドメイン設定を確認すると、下記のように DNS の設定をしろと、DKIM(Domainkeys Identified Mail) レコードの値を指定されますので、言われたとおりに DNS の TXT レコードとして設定します。

SparkPost のドメイン管理画面

「test」 を押して、問題なくレコードが登録されたことが確認できたら問題なし。先ほど控えた、API Key の情報を持って、サーバの設定ファイル (.env.production) に戻ります。

下記のように設定。SMTP_FROM_ADDRESS= に設定するのは、各メールの送信元となるアドレスです。

# E-mail configuration
# Note: Mailgun and SparkPost (https://sparkpo.st/smtp) each have good free tiers
SMTP_SERVER=smtp.sparkpostmail.com
SMTP_PORT=587
SMTP_LOGIN=SMTP_Injection
SMTP_PASSWORD=[先ほど取得した API Key]
SMTP_FROM_ADDRESS=example@mastodon.example.com
#SMTP_DELIVERY_METHOD=smtp # delivery method can also be sendmail
SMTP_AUTH_METHOD=plain
#SMTP_OPENSSL_VERIFY_MODE=peer
SMTP_ENABLE_STARTTLS_AUTO=true

ここまでで一旦設定ファイルの編集は終わりです。DB の設定などをして、Mastodon を立ち上げます。

DB の設定

ビルドして、立ち上げます。

# docker-compose build
# docker-compose up -d

立ち上がったら、DB コンテナに入って、DB の設定を行います。

# docker exec -it mastodon_db_1 bash

先ほど .env.production に設定した、下記の各情報を参考に、ユーザーと DB を作成します。

DB_USER=example
DB_NAME=example
DB_PASS=************

usernamedbname はそれぞれ必要なものに読みかえてください。

# su - postgres
$ createuser -P username
$ Enter password for new role:
$ Enter it again:
$ createdb dbname -O username
$ exit
# exit

マイグレーション等、実行してコンテナを再起動します。無事コンテナが立ち上がることを確認できたら、一旦 stop して次の作業へ。

# 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
# docker-compose stop

そろそろ仕上げの作業。次に SSL 証明書を取得して、nginx の設定を仕上げていきます。

Let's Encrypt を使用して SSL 証明書を取得、nginx の設定

以前、Let's Encrypt を使ってみた件については下記のエントリーで書いていますが、今回は nginx での運用ですので少し手順が異なります。

まず、Certbot クライアントを GitHub から取得します。ここでは /opt 以下にクライアントを置く前提で進めます。

# cd /opt
# git clone https://github.com/certbot/certbot

次に一旦 nginx をストップしてから、先ほど落としてきた Certbot クライアントを実行します。ちなみに、mastodon.example.com の部分は実際に SSL 証明書を使用するドメインに読みかえてください。

# systemctl stop nginx
# cd /opt/certbot
# ./certbot-auto certonly --standalone -d mastodon.example.com

メールアドレスを聞かれますので、確実に受信できるアドレスを入力して進めます。続いて利用規約が表示されますので問題なければ 「Agree」 すると証明書が取得できます。

証明書は /etc/letsencrypt/live/[指定したドメイン名]/ に保存されます。保存されるのは下記の 4ファイル。

  • cert.pem (サーバ証明書)
  • chain.pem (中間証明書)
  • fullchain.pem (上段:サーバ証明書 / 下段:中間 CA 証明書)
  • privkey.pem (秘密鍵)

証明書の更新を自動化

SSL 証明書の自動更新設定を行います。Let's Encrypt から発行される証明書は有効期限が 90日と短く、頻繁に更新が発生するので、更新作業を自動化しておかないと運用時に現実的ではありません。

私の環境では crontab に下記のように設定しておきました。

0 2,5 */7 * * root systemctl stop nginx && /opt/certbot/letsencrypt-auto renew --force-renew && systemctl start nginx

一旦、nginx を止めてから letsencrypt-auto renew--force-renew オプション付きで実行してあげれば、全証明書が一気に更新されます。一見雑な感じですが、通常はこれで問題ないです。

実行間隔は、7日に一度、夜中の 2時と朝 5時に 2回チャレンジするようにしてありますが、90日の間に 1回更新されればよいわけですから、月に 1回とかでもよいと思います。

なお、ドメインを指定して証明書の更新を実行したい場合などは、letsencrypt-auto certonly してあげればよいと思います。詳しくは下記のドキュメントなどを参考にしてみてください。

nginx の設定を仕上げ、SSL のセキュリティ設定も

SSL 証明書が手に入ったので、実際に立ち上げた Mastodon インスタンスが表示できるように nginx の設定を仕上げていきます。ついでに SSL 関連の設定もきちんとやって、Qualys の SSL Server Test で 「A+」 評価が出るようにしておきます。

まずは、nginx 用の設定ファイルを作成します。下記のように適当な名前を付けて設定ファイルを新規作成しましょう。

# vim /etc/nginx/conf.d/mastodon.example.com.conf

設定内容は下記のドキュメントを参考に。

参考までに、私の環境で実際に設定した内容は下記のようになります (一部 mastodon.example.com になっている部分は実際に使用するドメインに置き換えてください)。

なお、#gzip から下は、上記ドキュメントに書いてあるままのコピペです。

map $http_upgrade $connection_upgrade {
  default upgrade;
  ''      close;
}
 
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    return 301 https://$host$request_uri;
}
 
server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  server_name mastodon.example.com;
  root /home/mastodon/live/public;
  index index.html index.php index.xml;
 
  #ssl
  ssl_session_timeout 1d;
  ssl_session_cache shared:SSL:50m;
  ssl_session_tickets off;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_prefer_server_ciphers on;
  ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK';
  ssl_certificate /etc/letsencrypt/live/mastodon.example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/mastodon.example.com/privkey.pem;
  ssl_dhparam /etc/nginx/ssl/dhparam.pem;
  ssl_stapling on;
  ssl_stapling_verify on;
  ssl_trusted_certificate /etc/letsencrypt/live/mastodon.example.com/fullchain.pem;
  resolver 8.8.4.4 8.8.8.8 valid=300s;
  resolver_timeout 10s;
  add_header Strict-Transport-Security 'max-age=315360000;includeSubDomains;preload';
 
  #gzip
  gzip on;
  gzip_disable "msie6";
  gzip_vary on;
  gzip_proxied any;
  gzip_comp_level 6;
  gzip_buffers 16 8k;
  gzip_http_version 1.1;
  gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
 
  location / {
    try_files $uri @proxy;
  }
 
  location @proxy {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header Proxy "";
    proxy_pass_header Server;
 
    proxy_pass http://127.0.0.1:3000;
    proxy_buffering off;
    proxy_redirect off;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
 
    tcp_nodelay on;
  }
 
  location /api/v1/streaming {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header Proxy "";
 
    proxy_pass http://localhost:4000;
    proxy_buffering off;
    proxy_redirect off;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
 
    tcp_nodelay on;
  }
 
  error_page 500 501 502 503 504 /500.html;
}

Mastodon インスタンスのルートディレクトリは、/home/mastodon/live/public になりますので、そのように設定。80番ポートへのアクセスは、すべて 443 ポートにリダイレクトしてしまいます。

SSL 関連の設定は、下記などを参考にしながら決めています。

ssl_dhparam の設定がありますが、

ssl_dhparam /etc/nginx/ssl/dhparam.pem;

これについては、別途下記の通り作成しておきましょう。

# mkdir /etc/nginx/ssl
# cd /etc/nginx/ssl
# openssl dhparam 2048 -out dhparam.pem

SSL 関連の設定については、前述の通り、Qualys の SSL Server Test で 「A+」 評価が出ることを基準にしています。下記は実際にテストを通した結果。狙い通りです。

SSL Server Test (Powered by Qualys SSL Labs) による mastodon.burnworks.com のチェック結果

なお、nginx の default.conf については特にいじらず進めています。

Mastodon のアカウント作成、管理者設定

nginx の設定が完了したら、

# docker-compose up -d
# systemctl restart nginx

して、ブラウザでアクセスしてみましょう。Mastodon インスタンスが表示されれば成功です。速攻で最初のアカウントを取得しましょう。

Mastodon

メール設定が正しくできていれば、アカウント登録後、メールが届くはずです。もしメールが届かない場合は、下記のコマンドで強制的にメール認証を通してしまいましょう。

docker-compose run --rm web rails mastodon:confirm_email USER_EMAIL=[登録したメールアドレス]

次に登録したアカウントに管理者権限を付けます。サーバに戻り、下記のコマンドで先ほど作成した Mastodon アカウントに管理者権限を付与します。

# docker-compose run --rm web rails mastodon:make_admin USERNAME=[管理者にしたい username]

Mastodon に戻って、設定画面を開くと、管理者用メニューが表示されるはずです。

Mastodon の管理者専用設定画面

各項目は、クリックすると編集できますが、まず最初に 「新規登録を受け付ける」 の項目をクリックして 「無効」 にしましょう。これでアカウントの新規登録を一旦止めることができます。

次のステップで SINGLE_USER_MODEtrue にして、完全な自分専用インスタンスにしますが、ここまでで、ほぼ自分専用インスタンスが完成している状態になります。

例えば、少人数だけが参加するインスタンスが立てたければ、必要なアカウントを作成した後で 「新規登録を受け付ける」 を 「無効」 にしておけば、それ以上はアカウント登録されることがなくなるというわけです。

SINGLE_USER_MODEtrue

最初に作ったアカウント以外は一切作る予定はない、完全なシングルアカウントインスタンスとして運用するなら、下記の設定を行います。

# cd /opt/mastodon
# vim .env.production

として、設定ファイルを開き、下記の項目のコメントアウトを外してあげます。

SINGLE_USER_MODE=true

Docker コンテナと、nginx を再起動してあげれば、設定が反映されます。

# docker stop $(docker ps -a -q) && docker-compose up -d
# systemctl restart nginx

SINGLE_USER_MODEtrue にすると、トップページへのアクセスはすべて、accounts/1 のユーザーページにリダイレクトされ、/about ページからアカウントの作成ができなくなります (当たり前ですが登録済みアカウントでのログインはできます)。

これで完全な俺専用インスタンスのできあがりですね。シングルユーザーなので、当然ローカルタイムラインには自分の Toot (トゥート) しか流れてきませんけども。

アカウントのフォローはすべて 「リモートフォロー」 になります。投稿画面の上にある検索フォームに、

[username]@[instance-domain]

という形、例えば mstdn.jp 上の、burnworks をフォローしたければ、

burnworks@mstdn.jp

のように検索すると該当するユーザーが検索されますので、フォローボタンを押せばリモートフォローできます。

あるいは、自分のインスタンスにログインした状態で、リモートフォローしたい人のアカウントページを開き、「リモートフォロー」 ボタンを押した後、出てくる入力フォームに [自分のアカウント]@[自分のインスタンスのドメイン] と入力後、フォローボタンを押せば、リモートフォローできます。

実は Mastodon の日本語訳には当初、一部間違いがあって、上記の方法のリモートフォローをしようとしたとき [フォローしたい人のユーザー名]@[ドメインを入力してください] と表示されてしまっていましたが、前述の通り、ここに入れるのは 「自分の情報」 です。修正された翻訳はすでにマージされているようですので、徐々に直っていくとは思いますが。

例えば私が他のインスタンスのアカウントをフォローするときは下記のように入力します。

Mastodon リモートフォロー時の入力例

Mastodon のアップデート

最後に、Mastodon のアップデート手順を下記に (/opt/mastodon に必要なファイルがある前提)。基本的には一旦 Docker コンテナを stop した上で、git pull して、再度 build という手順。db:migrateassets:precompile については任意です。

# cd /opt/mastodon
# docker-compose stop
# git pull
# 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

ということで、俺専用インスタンスを さくらの VPS 上に立ち上げるまでの手順でした。書いてみたら長かった......

とはいえ、今回のような小規模インスタンスであれば、Docker のおかげでかなり楽に立ち上げることができます。

実際に運用してみてどの程度サーバに負荷がかかるのかなどは、ちょっと様子を見ながらだと思いますが、自分専用ならまぁその辺は気楽にいけるのでいいかなと。別に落ちたところで困るのは自分だけですからね。

あと、自分専用インスタンスだと、カスタマイズなんかもやろうと思えば自由にできるので、その辺も落ち着いたら試してみようかなと思います。あまりいじりすぎるとアップデート等が面倒になるのでほどほどにしておく方がよいとは思いますが。

ちなみに、私は mstdn.jp にもアカウントを持っていますが、自分で立てたインスタンスから、mstdn.jp 上の自分をフォローする行為はなんていうかちょっと新鮮でしたよ。

なお、大規模インスタンスの運用については、企業としていち早くインスタンスの運用に乗り出した pixiv さんの下記の記事が参考になります。

参考にさせていただいたページ

関連エントリー