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 の設計思想自体は特に目新しいものではなく、同じく 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 レコードとして設定します。
「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=************
username
と dbname
はそれぞれ必要なものに読みかえてください。
# 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+」 評価が出ることを基準にしています。下記は実際にテストを通した結果。狙い通りです。
なお、nginx の default.conf については特にいじらず進めています。
Mastodon のアカウント作成、管理者設定
nginx の設定が完了したら、
# docker-compose up -d # systemctl restart nginx
して、ブラウザでアクセスしてみましょう。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 に戻って、設定画面を開くと、管理者用メニューが表示されるはずです。
各項目は、クリックすると編集できますが、まず最初に 「新規登録を受け付ける」 の項目をクリックして 「無効」 にしましょう。これでアカウントの新規登録を一旦止めることができます。
次のステップで SINGLE_USER_MODE
を true
にして、完全な自分専用インスタンスにしますが、ここまでで、ほぼ自分専用インスタンスが完成している状態になります。
例えば、少人数だけが参加するインスタンスが立てたければ、必要なアカウントを作成した後で 「新規登録を受け付ける」 を 「無効」 にしておけば、それ以上はアカウント登録されることがなくなるというわけです。
SINGLE_USER_MODE
を true
に
最初に作ったアカウント以外は一切作る予定はない、完全なシングルアカウントインスタンスとして運用するなら、下記の設定を行います。
# 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_MODE
を true
にすると、トップページへのアクセスはすべて、accounts/1
のユーザーページにリダイレクトされ、/about ページからアカウントの作成ができなくなります (当たり前ですが登録済みアカウントでのログインはできます)。
これで完全な俺専用インスタンスのできあがりですね。シングルユーザーなので、当然ローカルタイムラインには自分の Toot (トゥート) しか流れてきませんけども。
アカウントのフォローはすべて 「リモートフォロー」 になります。投稿画面の上にある検索フォームに、
[username]@[instance-domain]
という形、例えば mstdn.jp 上の、burnworks をフォローしたければ、
burnworks@mstdn.jp
のように検索すると該当するユーザーが検索されますので、フォローボタンを押せばリモートフォローできます。
あるいは、自分のインスタンスにログインした状態で、リモートフォローしたい人のアカウントページを開き、「リモートフォロー」 ボタンを押した後、出てくる入力フォームに [自分のアカウント]@[自分のインスタンスのドメイン]
と入力後、フォローボタンを押せば、リモートフォローできます。
実は Mastodon の日本語訳には当初、一部間違いがあって、上記の方法のリモートフォローをしようとしたとき [フォローしたい人のユーザー名]@[ドメインを入力してください]
と表示されてしまっていましたが、前述の通り、ここに入れるのは 「自分の情報」 です。修正された翻訳はすでにマージされているようですので、徐々に直っていくとは思いますが。
例えば私が他のインスタンスのアカウントをフォローするときは下記のように入力します。
Mastodon のアップデート
最後に、Mastodon のアップデート手順を下記に (/opt/mastodon
に必要なファイルがある前提)。基本的には一旦 Docker コンテナを stop
した上で、git pull
して、再度 build
という手順。db:migrate
と assets: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 さんの下記の記事が参考になります。
参考にさせていただいたページ
関連エントリー
- いいね!で最新情報を取得
この記事が気に入ったらいいね!してください。
Facebook で最新の記事をお届けします。