自分用にマストドンインスタンスを立てました。→ https://radon.lpha-z.net
いろいろとさびしいので、遊びに来てくれるとうれしいです。
Twitterの方を動かさなくなるというわけではないです。
さて、マストドンインスタンスを立てたい誰かの助けになればと思って、やったことをメモしておきます。
注意点として、私はネットワーク方面の知識を全く持っていないので、結構まずいことをやっているかもしれないです。
そういう点の指摘があれば、コメント欄に書いていただけると助かります(大歓迎です)。
基本的には知識ゼロでできるはずですが、Linux系のコマンドを全く叩いたことがないという場合は少し難しいかもしれません(もちろん、手順通りやればいいのですが、やってることの意味が全くわからないと、間違った時に解決方法がわからないかもしれません)。
要約
- サーバーは、AWSを使う(一年間は無料でできます)
- ロードバランサーとかデータベース用サーバーとかは使わないで、EC2のインスタンス一個でやる(私がよくわからないのと、小規模ならその方がお金もかからないし……)
- 自分用のドメインが必要です(一年間で1000円とか2000円とかそこらです)
手順
まずはAWSのアカウントを作りましょう。クレジットカードの登録が必要ですが、無料の範囲内でやっていきます。
次に、以下の記事の3.までを読んでAWSに関する知識を得ながら構築を進めます。注意としては、4.以降にかかれている情報は古い(前にマストドンが流行った2017年4月ごろのものにもとづいている)ので、そこは行いません。あと、ドメインをRoute53で入手したり、Amazon Certificate ManagerでSSL証明書を入手したり*1、Hosted Zoneの設定をしたりは今回はやりません。
AWSでMastodonインスタンスを作るまで。自分まとめ
上の記事ではAMIの選択とインスタンスタイプが説明されていません。立てるスタンスは、Ubuntu Server 18.04LTSが良いようなのですが、無料の範囲内にそういったのがないので、.NET Core 2.1 with Ubuntu Server 18.04 - Version 1.0 (ami-6ccaa781)
を選びました。本当にこれでいいのかな?インスタンスタイプは、無料になっているt2.microを選びました。
上の記事と異なる点として、セキュリティグループの設定では、HTTPとHTTPSも許可します。HTTPはなくてもよいような気がします。
自分用のドメイン(なんとか.comとか、そういうやつです。私のだとlpha-z.net)を手に入れます。私はお名前.comで取得しました。特にこれを推奨しているわけではありませんが、以下の説明はお名前.com特有の説明になります。DNSについての最低限の知識があれば、他のところで取得しても、以下の手順を適当に自分の取得したところ用の手順に読み替えて行えるはずです。そういったサービスがないのなら、Route53でやればよいような気もします。0.5ドルかかるらしいです。
ドメインを入手した後、ログインします。DNSのタブを開きます。DNSレコード指定で、自分のマストドンインスタンスのホスト名(私のだとradon.lpha-z.net。.lpha-z.netはすでに入っているのでradonとだけ入力)を入力します。TYPEはAとして、TTLはなんでもよいのでとりあえずデフォルトのままにしておきます。VALUEは、EC2のインスタンスに割り当てられたIPv4 パブリックIPを入力します。
ところで、ここで入力するホスト名は、マストドンインスタンスを立ち上げてから変えようと思うと面倒なことになるので、慎重に決めた方が良いです。マストドンアカウントは、それ込みになっているからです。
ネット上にある記事は、ほとんど2017年4月ごろのものなので(大事なことなので二回言いました)、参考にすると痛い目にあいます。
公式のドキュメント
documentation/Production-guide.md at master · tootsuite/documentation · GitHub
を眺めながら行いましょう。
以下、手順を詳しく説明します。上のドキュメントに、私の理解での補足説明を加えていますが、怪しい部分が多いと思います。Linuxの知識が少しでもあり、英語が全く読めないというわけではなければ、上のドキュメントを見れば十分だと思われます。
ちなみに、大慌てでやっても一時間くらいかかります。
スワップファイルの設定をする
最後の方の「コンパイル」のところでメモリが足りなくなると困るので、念のためスワップファイルの設定をしておきます。t2.microのメモリ量だと本当にぎりぎりのようです。
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
依存しているソフトウェアをインストールする
この部分はrootユーザーでやってくださいと書いてあります。これは、ubuntuであれば、sudo
をつけて実行してくださいという風に読み替えれば十分です。以下の説明では必要なところにsudo
を加えて説明していますから、その通りに入力すれば大丈夫なはずです。
node.jsを入れる
node.jsとは、サーバーサイドJavaScript環境だそうです(Wikipedia)。
まず、
sudo apt -y install curl
でcurl
というアプリケーションをインストールします。おそらく、これは更新不要と出るはずです。
次に、
curl -sL https://deb.nodesource.com/setup_8.x | sudo bash -
と入力してnode.jsをインストールします。sudo
の位置はここです。これは、このURLから入手したスクリプトを実行するというコマンドになっています。
何が送り付けられてくるのかはよくわかりませんが、とにかくよしなにやってくれるようです。
yarnを入れる
yarnはJavascript用のパッケージマネージャーだそうです。以下のコマンドを入力し手インストールします。
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt update
入力ミスに気を付けます。入力ミスをしてもOK
などと表示されるのですが、以降の手順でエラーになってしまうという罠が存在します(私は引っかかりました)。
こちらは得体のしれないスクリプトを実行するのではなく、apt
というパッケージマネージャーを通して行っているようです。
その他の依存関係を入れる
そのほかの、apt
コマンドで入れられるものをたくさん入れます。
sudo apt -y install imagemagick ffmpeg libpq-dev libxml2-dev libxslt1-dev file git-core g++ libprotobuf-dev protobuf-compiler pkg-config nodejs gcc autoconf bison build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm5 libgdbm-dev nginx redis-server redis-tools postgresql postgresql-contrib certbot yarn libidn11-dev libicu-dev
以上のコマンドは長いですが、間違いなくコピペして入力し、実行します。
私は、コピペの際に後ろが途切れてしまい、以下の手順でruby
がコンパイルできないだのpostgresqlなんてアカウントはないだのと怒られるドジを踏みました……。
たくさんインストールするので、二分ちょっと時間がかかります。
特権ユーザーじゃなくてもできる依存関係を入れる
準備
今までの手順は、Ubuntu本体に(?)いろいろインストールしていました。マストドンでは、Rubyの特定のバージョンを使っています。こういう時に、Ubuntu本体にその特定のバージョンのRubyを入れてしまうと、ほかのバージョンのRubyを使いたいという場合、困ってしまいます。ここで、特定のバージョンのRubyを、自分でコンパイルして自分だけが使えるようにしてしまえば、その問題は発生しません。そんなことを実現するのがrbenvだそうです。
こういうとき、ユーザーを分けて行えば、何も指定しなかった時のruby
コマンドが自前コンパイルしたruby
になるようにそのユーザーの環境変数に指定しておくことで、rbenvを使っていることを意識せずに行うことができます。
というわけでユーザーを作ります。
sudo adduser mastodon
ドキュメントには書いていませんが、ここでパスワードを決める必要があります。以降使わないので、適当に決めます。住所とかわけのわからないことを聞かれますが、単にエンターを押すだけでスキップできますので、飛ばします。
ユーザーmastodonとしてログインします。
sudo su - mastodon
ログインできました。続いて、次の手順を行います。ここからはsudo
は必要ありません(むしろ使えません)。
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
cd ~/.rbenv
src/configure
make -C src
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
exec bash
type rbenv
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
rbenvをgithubから持ってきて、ruby
をビルドする準備を整えました。
type rbenv
を実行すると関数みたいなものが出てくれば大丈夫なのだと思います(答えが載っていないのでわからないのですが、私がやったらそうなりました)。
Ruby2.5.1を使えるようにする
Rubyをコンパイルします。
rbenv install 2.5.1
コンパイルには五分ほど時間がかかります。止まっているように見えますが、ゆっくり待ちます。
rbenv global 2.5.1
どこでもruby2.5.1を使えるようにするという意味っぽいです(?)
マストドンの依存関係をインストールする
まず、マストドンのリポジトリを持ってきます。ホームディレクトリの下のlive
というディレクトリに入れることにします。
cd ~
git clone https://github.com/tootsuite/mastodon.git live
cd ~/live
マストドンのmasterブランチは、開発中でいろいろバグが含まれているので、安定板を使います。以下のコマンドは、自動的に最新のバージョンを判定してそれを使えるようにするワンライナーになっています。
git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)
長いですね。今だと最新版はv2.4.3なので、実質的にはgit checkout v2.4.3
と同じになります。
以下のコマンドを入力して、依存関係をいろいろインストールします。gem
とかbundle
が何をやっているのかは知りませんが、まぁなんかうまい具合に依存関係を解決してくれているようです。
gem install bundler
bundle install -j$(getconf _NPROCESSORS_ONLN) --deployment --without development test
-j$(getconf _NPROCESSORS_ONLN)
の部分は、並列化オプションだと思われますが、t2.microのインスタンスだと1coreしか使えないので、指定する意味ないような気がします。
大体三分くらいかかりました。
yarn install --pure-lockfile
これには一分くらいかかりました。ところで、以下のように表示される場合、yarn
のインストールをミスっています(先ほど書いた、私の踏んだドジです……)。
Usage: yarn [options]
yarn: error: no such option: --pure-lockfile
この後の作業は、また特権が必要な作業になります。そこで、以下のコマンドでubuntuユーザーに戻りましょう。
exit
サーバーのいろいろな設定
PostgreSQLというのは、データベースを管理するソフトウェアです。マストドンのいろいろなデータをうまいこと保存してくれるようです。その設定を行っていきます。
sudo -u postgres psql
postgresというユーザーとして、psql
コマンドを実行するという意味っぽいです。すると、いつもと違ったプロンプト(入力待ってますマーク)が出ますので、
CREATE USER mastodon CREATEDB;
と入力します。これで仕事は終わりで、このプロンプトから脱出するために
\q
と入力してもとのbashに戻ってきます。
nginxの設定
nginx(えんじんえっくす、と読むらしい)は、webサーバーのソフトウェアです。HTTPSアクセスが来たら何を返すべきか、とかそういったことの設定を行います。
sudo nano /etc/nginx/sites-available/example.com.conf
でその設定ファイルを開きます。そのあと、以下のテキストを入力します。ただし、 example.com
になっている部分は、全て自分のホスト名に置き換えてください。四か所あります。
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
listen [::]:80;
server_name example.com;
root /home/mastodon/live/public;
# Useful for Let's Encrypt
location /.well-known/acme-challenge/ { allow all; }
location / { return 301 https://$host$request_uri; }
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com;
ssl_protocols TLSv1.2;
ssl_ciphers HIGH:!MEDIUM:!LOW:!aNULL:!NULL:!SHA;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
keepalive_timeout 70;
sendfile on;
client_max_body_size 8m;
root /home/mastodon/live/public;
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;
add_header Strict-Transport-Security "max-age=31536000";
location / {
try_files $uri @proxy;
}
location ~ ^/(emoji|packs|system/accounts/avatars|system/media_attachments/files) {
add_header Cache-Control "public, max-age=31536000, immutable";
try_files $uri @proxy;
}
location /sw.js {
add_header Cache-Control "public, max-age=0";
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://127.0.0.1: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;
}
保存してからエディタを終了したいので、下の説明を見ます。^O
でWriteOutだと書いてありますね。これは、コントロールキーとOキーを同時に押してくださいという意味です。
cd /etc/nginx/sites-enabled
sudo ln -s ../sites-available/example.com.conf
よくわかりませんがシンボリックリンクを作成して、完了です。
Let's encryptを利用してSSL証明書を取得する
HTTPSでセキュアな通信をするためには、SSL証明書が必要です。Let's encryptを使うと手軽にSSL証明書を取得できます。
まず、nginxが動いている状態では行えない(止めてくださいと怒られる)ので、以下のコマンドで停止させます。
sudo systemctl stop nginx
次に、以下のコマンドでSSL証明書を取得します。もちろん、example.comの部分は作ろうとしているマストドンインスタンスのホスト名に書き換えてください。
sudo certbot certonly --standalone -d example.com
まず、メールアドレスを聞かれるので、マストドン用に使いたいメールアドレスを入力します(私はgmailアカウントを一つ作成しました)。規約に同意するかを聞かれますから、同意する場合はAを入力します(同意しないとSSL証明書は手に入りません)。宣伝メール(?)を送っていいか聞かれますが、ここはYでもNでも問題なさそうです。これでSSL証明書が手に入り、適切な位置に配置されます。
sudo systemctl start nginx
さっき停止させたnginxを再開させます。もし、ここで変なエラーが出る場合、先ほど作ったnginxの設定ファイルが間違っている可能性があります(たとえば、example.comのままだったりするとそうなります)。
sudo certbot certonly --webroot -d example.com -w /home/mastodon/live/public/
証明書を更新するか聞かれます。公式ドキュメントによれば、ここは更新する(2を入力する)を選んでくださいと書いてありますが、更新しない(1を入力する)を選んでもうまく動きました。ちなみに、更新するのは一週間に五回くらいしか行えないらしいので、変なことになったからまた一からやり直そうみたいなことを繰り返しやっているとエラーになります。
Let's encryptで手に入れたSSL証明書は、90日で失効してしまい更新が必要になります。いちいち手作業でやるのは面倒ですので自動化させましょう。定期的にコマンドを実行してくれるcron
を使います。まず以下のように設定ファイルを編集します。
sudo nano /etc/cron.daily/letsencrypt-renew
ここに以下に示したような、自動実行すべきスクリプトを入力し……
#!/usr/bin/env bash
certbot renew
systemctl reload nginx
さっきと同じように保存してエディタを終了させます。ところで、このスクリプトの中にはsudo
が書かれていません。これで大丈夫なのかという感じですが、crontab
ではなく直に作成しているので大丈夫なんだと思います(たぶん……)。crontab
を使った場合はそのユーザーの権限で実行されるため、sudo
が必要です。
sudo chmod +x /etc/cron.daily/letsencrypt-renew
sudo systemctl restart cron
先のスクリプトファイルに実行権限を与え、cron
を再起動しておきます。
またmastodonユーザーになりましょう。
sudo su - mastodon
全体の設定
以下のコマンドで、いろいろな設定を行ってくれるウィザードが出てきます。
cd ~/live
RAILS_ENV=production bundle exec rake mastodon:setup
Domain name
のところは、ホスト名を入れます。
Do you want to enable single user mode?
のところは、「おひとり様インスタンス」にしたいかを聞かれていますので、Y/Nで答えます。私はNを選んだので、radon.lpha-z.netは私以外でも登録できます。
Are you using Docker to run Mastodon?
のところは、Docker上で動かすかを聞かれています。どちらがいいのかわからないので、Docker上で動かさない(N)を選びました。
以下、PostgresSQL(データベース)とRedis(キャッシュらしい)の設定が始まりますが、デフォルトの設定で問題ありません。エンターを押せばデフォルトの設定になります。合計7回エンターを押します。
Do you want to store uploaded files on the cloud?
の部分では、画像などを外部サーバーに保存するかを聞かれていますが、設定も面倒なのでローカルに保存することにします。Nを入力しました。
Do you want to send e-mails from localhost?
の部分では、メールをこのサーバーから送るかを聞かれています。以下の説明はかなり怪しいです。
どうもEC2のサーバーからメールを送信するのは、スパムメールの問題から面倒事が多いらしいです。そこで、自前のgmailアカウントから送信することにします。
上のような設定でうまくいきました。ただし、gmailの設定で「安全性の低いアプリからのアカウントへのアクセスを許可する」をオンにしておく必要があります。また、Let's encryptの証明書をとった時のメールアドレスでないと、テストメールは送信できても本番のメールが送信できないようなトラブルが発生しました(原因はよくわかりませんが)。そもそも、plain, noneになっているのって本当はやばい設定になっているんでしょうか……?あと、メールのパスワードが設定ファイルに平文で書かれるのはちょっと気持ち悪い……。
この設定をした後、テストメールを送るか聞かれますので、適当なメールアドレスを入力して、送信できるかと受け取れるかを確認します。パスワードの入力があっているかを二回入力で確かめたりしていないので、これはやった方が良いです。
Save configuration?
とこの設定を保存するか聞かれますから、Yと答えます。ここでNと答えると、今まで入力したのが全部破棄されて一からやり直しになるので注意しましょう。
データベースの初期化
Prepare the database now?
と聞かれるので、Yと答えてデータベースを初期化しましょう。ところで、いったんデータベースを作った後、諸事情があって一からやりなおしたばあい、既にデータベースがあるということで、上書きされるのではなく、エラーが出ます。その場合は、RAILS_ENV=production bundle exec rake mastodon:setup
ではなく、RAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1 bundle exec rake mastodon:setup
とすることで、エラーにならないで上書きすることができます。
手で書いたJavascriptファイルは変数名が長く処理が遅いらしいです。そのため(?)、コンパイルを行って必要最低限のJavascriptファイルにするようです(?)。あるいは、Javascriptではない言語で書かれたコードをJavascriptに変換することをコンパイルと呼んでいるのかな?いずれにせよ、コンパイルをやるらしいです。これには五分くらいかかります。メモリがたくさん必要になります。t2.microだと最初のスワップファイル作成を忘れているとコンパイルできないかも。
Adminアカウントの作成
マストドン上でのAdminアカウントを作成します。アカウント名とメールアドレスを入力すると、仮のパスワードが出てくるので、これを使ってログインすることができます。メールアドレスはログインするときに必要になります(ログインするときに必要なのはアカウント名ではないです)。仮のパスワードは、初回ログイン後に変えておきましょう。
これで設定はおしまいです。特権ユーザーに戻りましょう。
exit
マストドンのサービス用のデーモンを作る
マストドンのウェブページにアクセスしたときには、単に静的なページを表示するだけではなく、いろいろな仕事をする必要があります。たとえば、トゥートしたからそれをデータベースに書き込んで、とかいう要求が一例です。そういった要求を待ち構えているプロセス(デーモン)を作る必要があります。
まず、
sudo nano /etc/systemd/system/mastodon-web.service
で設定ファイルをエディタで開き、以下の内容を書き込んで保存。
[Unit]
Description=mastodon-web
After=network.target
[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="RAILS_ENV=production"
Environment="PORT=3000"
ExecStart=/home/mastodon/.rbenv/shims/bundle exec puma -C config/puma.rb
ExecReload=/bin/kill -SIGUSR1 $MAINPID
TimeoutSec=15
Restart=always
[Install]
WantedBy=multi-user.target
同様に、
sudo nano /etc/systemd/system/mastodon-sidekiq.service
で以下を入力して、
[Unit]
Description=mastodon-sidekiq
After=network.target
[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="RAILS_ENV=production"
Environment="DB_POOL=5"
ExecStart=/home/mastodon/.rbenv/shims/bundle exec sidekiq -c 5 -q default -q mailers -q pull -q push
TimeoutSec=15
Restart=always
[Install]
WantedBy=multi-user.target
さらに
sudo nano /etc/systemd/system/mastodon-streaming.service
で以下を入力して
[Unit]
Description=mastodon-streaming
After=network.target
[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="NODE_ENV=production"
Environment="PORT=4000"
ExecStart=/usr/bin/npm run start
TimeoutSec=15
Restart=always
[Install]
WantedBy=multi-user.target
以上の三つの設定ファイルを作りました。
これらを以下のコマンドで有効にします。
sudo systemctl enable /etc/systemd/system/mastodon-*.service
で、これらを開始します。
sudo systemctl start mastodon-*.service
以下のコマンドで、動いているかを確認します。
sudo systemctl status mastodon-*.service
なぜか何も出てきません。
これはUnixの「何も出てこなければ正常」ではありません。実際に動いていません。
これはよくわからないのですが、以下のように個別に開始することで、動くようになりました。なんで?
sudo systemctl start mastodon-web.service
sudo systemctl start mastodon-sidekiq.service
sudo systemctl start mastodon-streaming.service
古い画像とかのキャッシュを消す
他のインスタンスから流れてきたトゥートに添付されている画像や動画は、自分のサーバーにキャッシュされますが、延々たまっていくと邪魔なので、それを定期的に削除するcron
を書いておきましょう。
crontab
で作ったスクリプトは、設定を作ったユーザーの権限で行われます。
sudo su - mastodon
crontab -e
でエディタの選択肢が出るので好きなエディタを選んで
RAILS_ENV=production
@daily cd /home/mastodon/live && /home/mastodon/.rbenv/shims/bundle exec rake mastodon:media:remove_remote
を入力して保存して終了します。
以上の手順で自分のマストドンインスタンスを立てることができるはずです。
公式のドキュメントがもれなく書いてあるので、それを読めばネットワークなどの知識がなくても動かすことができます。
マストドンを使った雑感とか、改造した部分とかについても書こうと思ったのですがまた別のブログ記事で書くことにします。
あとさみしいので私のマストドンインスタンスにも遊びに来てください……。
radon.lpha-z.net