はじめに
某青い鳥の SNS がにわかに先行き不安なので、Mastodon を構築してみました。その備忘録です。
実は以前にも一度構築していましたが放置状態1だったので、改めてやり直してみます。
この手順に従って実際に構築したサイトは以下となります。
環境
とりあえずはお遊びなのでケチケチの方針で。
項目 | 備考 | |
---|---|---|
OS | Rocky Linux 9.12 | RHEL 9.1 のバイナリ互換 |
Mastodon | 4.0.2 | 2023/02/08 時点での最新版 |
マシン環境 | WebARENA Indigo 1GB | 月額 349 円の VPS RAM 1GB・SSD 20GB・vCPU 1コア |
ドメイン名管理 | Value Domain | |
メール配送 | XREA | Value Domain と同じ会社のサービス |
作業手順
基本的には公式手順に従います。
ただし、公式手順は Ubuntu を想定して書かれているので、RHEL 系では読み替えが必要になります。
Indigo でインスタンスを立ち上げる
公開鍵認証用の鍵を作成する
ローカル環境で生成する
SSH 接続用の鍵を用意します。
PuTTY3 付属の puttygen.exe を用いる場合、こんな感じ。
- 生成する鍵の種類として「RSA」を選択する4 (いわゆる SSH-2 RSA となる)。
- 「生成」をクリックする。マウスを適当にグリグリ動かしていると完了する。
- 「OpenSSHのauthorized_keysファイルにペーストするための公開鍵」欄の文字列をコピーして、テキストエディタなどで保存しておく。
- 「公開鍵の保存」ボタンで、公開鍵を保存しておく。
- 「秘密鍵の保存」ボタンで、秘密鍵を保存しておく (拡張子は .ppk)。
公開鍵を VPS サービス側に登録する
Indigo コントロールパネルの「インスタンス管理」-「SSH鍵」を開き、右側の「SSH鍵のインポート」を選ぶ。
先ほど保存した「OpenSSHのauthorized_keysファイルにペーストするための公開鍵」欄の文字列を貼り付ける。
鍵名は適当で OK(鍵のコメントと揃えておくといいかもしれません)。
最後に「作成」を押してインポート完了。
「インスタンス管理」-「SSH鍵」に戻り、先ほど追加した鍵が一覧表示されていれば OK。
うまく行かない場合、RSA 以外の鍵を使用していないか確認すること
インスタンスを起動する
「インスタンス管理」-「インスタンス」メニューの、右側の「インスタンスの作成」をクリック。
以下のような選択画面が表示されるので、インスタンスの構成を選択する。
- イメージは Rocky Linux 9.0。
- インスタンスのサイズは 1 vCPU / 1 GB RAM / 20 GB SSD / 100 Mbps。月 349 円のプランになる。
- SSH 鍵は先ほどアップロードしたものを選ぶ。
- インスタンス名は他と区別が付く名前を適当に。
- 選択し終わったら、「インスタンスの作成」をクリック。
作成が始まると「OS のインストール中」のような表示が出るので、数分待ちます (なぜか手元ではOS インストールが終わっても表示が更新されないので、いったん別のタブを開いてから戻ってくる必要がありました…)。
先ほど作成したインスタンスが「Stopped」と表示されているので、
- IP アドレスを記録しておきます。
- 右端の「選択」を展開します。
- 「インスタンスの起動」を選びます。
SSH 接続してみる
Indigo の Rocky Linux イメージの場合、デフォルトで rocky というユーザが作成されています。
https://help.arena.ne.jp/hc/ja/articles/360049807634/
先ほど設定した SSH の鍵を使って接続してみます。
ここまでで、素の状態のインスタンスが起動しました。
SSH 接続用のポートを変更する
デフォルトの port 22 はブルートフォース攻撃の定番なので、負荷軽減と心理的安心も兼ねて変更しておきます。
(ポート番号が分かれば攻撃可能なので、悪意を持った攻撃者に対しては意味ないですが)
# SELinux about this change.
# semanage port -a -t ssh_port_t -p tcp #PORTNUMBER
#
-#Port 22
+Port 60022
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
「ポート番号を変更するときは SELinux の設定も変更してね」とのコメントに従い、スーパーユーザで以下を実行します。
# semanage port -a -t ssh_port_t -p tcp 60022
# systemctl restart sshd
※まだ port 22 で接続しているセッションは閉じないで!
この状態で、port 60022 で SSH 接続してみて繋がれば OK。
もし繋がらなければ /etc/ssh/sshd_config
の記述と、semanage
で設定した内容、さらに Indigo コントロールパネルのファイアウォールの設定が合ってるか確認を。
semanage
の設定内容は以下で確認できます。
# semanage port -l | grep ssh_port_t
ssh_port_t tcp 60022, 22
ファイアウォールの設定をする
標準だと (Indigo 側、インスタンスの OS 自体のいずれも) 何も制限されていないようなので、まずはファイアウォールを設定します。
まず、Indigo コントロールパネルの「ネットワーク管理」-「ファイアーウォール」より、「ファイアーウォールの作成」をクリックします。
ファイアーウォール作成画面に移ったら、以下を行います。
- 任意の名前を付ける。
- 「新規ルール」ボタンをクリックして、「HTTP」「HTTPS」「Custom」を一回ずつ選ぶ。
- 「Custom」のポート番号欄に「60022」(SSH のポート番号)を入力する。
- 「IPアドレス」欄に「0.0.0.0」を入力する。
- 「インスタンスへの適用」欄は、先ほど立ち上げたインスタンスの名前を選ぶ。
- 「作成」をクリックする。
上記の作業が正しく行われていれば、新たに SSH 接続を開始しても正常につながるはずです。
作業用のユーザを作成する
SSH で接続するためのユーザ (ここでは yamazaki
) を作成します。
# groupadd -g 1001 yamazaki
# useradd -g 1001 -u 1001 yamazaki
# passwd yamazaki
passwd yamazaki
は任意。
やっておけば万が一 SSH で繋がらなくなった場合(ex. ファイアウォールの設定を間違えた時)に VPS のコンソールからローカルログインできます。
デフォルトユーザの所属グループをコピーします。
# id rocky
uid=1000(rocky) gid=1000(rocky) groups=1000(rocky),4(adm),190(systemd-journal)
# usermod -aG adm,systemd-journal yamazaki
# id yamazaki
uid=1001(yamazaki) gid=1001(yamazaki) groups=1001(yamazaki),4(adm),190(systemd-journal)
sudoers
に追加します。
yamazaki ALL=(ALL) NOPASSWD: ALL
上記の設定だと $ sudo
実行時にパスワードを聞かれなくなります。
パスワードを聞かれたい場合は yamazaki ALL=(ALL) ALL
で。
# chmod 0640 /etc/sudoers.d/99-nopasswd
公開鍵認証できるように、公開鍵をコピーします。
# su - yamazaki
$ mkdir -m 0700 ~/.ssh
$ echo "ssh-rsa AAA...xyz ssh2-rsa-2023-02-12" >> ~/.ssh/authorized_keys
$ chmod 0600 ~/.ssh/authorized_keys
この状態で、公開鍵で SSH ログインでき、sudo su -
でスーパーユーザに昇格できることを確認します。
標準ユーザを削除する
最初から作成されていたユーザ rocky
を削除します。
# userdel -r rocky
-r
: ホームディレクトリとメールスプールも削除。
sudoers
から、末尾の rocky
で始まる行を削除します。
# vi /etc/sudoers
なぜかこっちにも居るので削除します。
# rm /etc/sudoers.d/90-cloud-init-users
事前準備
OS・アプリケーションを最新にする
# dnf check-update
# dnf update
# reboot
2023/02/12 時点では、Rocky Linux 9.1 になりました。
基本的なサーバ全体の設定
タイムゾーン
# timedatectl set-timezone Asia/Tokyo
ロケール
# dnf install glibc-locale-source
# localedef -f UTF-8 -i ja_JP ja_JP
ホスト名
ホスト名は mstdn.yamachan.org
とします。
# hostnamectl set-hostname mstdn.yamachan.org
その他
デフォルトだと vi エディタがショボくて扱いづらいので
# dnf install vim
メモリ周りに余裕を持たせる
kdump を無効化する
1GB プランなのに、free
の結果表示される total
欄は 0.75GB 弱しかありません。
$ free
total used free shared buff/cache available
Mem: 783012 218668 521272 5708 161148 564344
Swap: 0 0 0
RHEL 9 系の仕様で kdump のためにメモリを予約しているのが原因なので、kdump を無効化します。
詳細は以下を参照してください。
スワップを有効化する
スワップファイルを使用することで、メモリが足りなくなるのを回避します。
# dd if=/dev/zero of=/swapfile bs=1M count=1024
# chmod 0600 /swapfile
# mkswap /swapfile
# swapon /swapfile
ここまででスワップファイルが有効になりました。
free
実行時に以下のようになっていれば OK。
$ free
total used free shared buff/cache available
Mem: 979620 242144 67544 4488 815312 737476
Swap: 1048572 0 1048572
Mem:
の total
が 1GB 弱、Swap:
が 1GB になっています。
再起動後も適用されるように、以下の行を fstab
に追記します。
/swapfile none swap sw 0 0
Mastodon の導入
拡張リポジトリの導入
EPEL
# dnf install epel-release
RPM Fusion
# dnf install https://mirrors.rpmfusion.org/free/el/rpmfusion-free-release-9.noarch.rpm
# dnf install https://mirrors.rpmfusion.org/nonfree/el/rpmfusion-nonfree-release-9.noarch.rpm
CRB
# dnf config-manager --set-enabled crb
必要なツール類を入れる
wget
# dnf install wget
ImageMagick
# dnf install ImageMagick
FFmpeg
# dnf install ffmpeg ffmpeg-devel
Redis
# dnf install redis
# systemctl enable redis
# systemctl start redis
PostgreSQL
# dnf install postgresql postgresql-server libpq-devel
# su - postgres
postgres$ initdb --encoding=UTF-8 --no-locale -D /var/lib/pgsql/data
postgres$ exit
# systemctl enable postgresql
# systemctl start postgresql
nginx
# dnf install nginx
有効化はまた後で。
Node.js
# dnf install nodejs
yarn5
# npm uninstall -g yarn pnpm
# npm install -g corepack
# corepack enable
# yarn set version classic
その他もろもろ
https://docs.joinmastodon.org/admin/install/#system-packages で足りないものを
Ubuntu でのパッケージ名 | RHEL 系でのパッケージ名6 |
---|---|
libprotobuf-dev | protobuf-devel |
protobuf-compiler | protobuf-compiler |
certbot | certbot |
python3-certbot-nginx | python3-certbot-nginx |
libicu-dev | icu, libicu-devel |
libidn11-dev | libidn-devel |
postgresql-contrib | postgresql-contrib |
gcc, g++ | gcc-c++ |
git-core | git-core |
libssl-dev | openssl-devel |
zlib1g-dev | zlib-devel |
libreadline6-dev | readline-devel |
libjemalloc-dev | jemalloc-devel |
# dnf install protobuf-devel protobuf-compiler certbot python3-certbot-nginx \
icu libicu-devel libidn-devel postgresql-contrib gcc-c++ git-core \
openssl-devel zlib-devel readline-devel jemalloc-devel
事前設定変更
ユーザ mastodon を作成する
OS ユーザ mastodon
を作成します。
Redis と Unix ドメインソケット経由で通信させるため、redis
グループに追加します。
# groupadd -g 9001 mastodon
# useradd -g 9001 -u 9001 mastodon
# usermod -aG redis mastodon
PostgreSQL ユーザの作成とパスワード設定
PostgreSQL ユーザ mastodon
を作成し、特権ユーザ (postgres
) と mastodon
にパスワードを設定します。
# su - postgres
postgres$ psql
postgres=# CREATE USER mastodon CREATEDB;
CREATE ROLE
postgres=# alter user postgres with password 'password-for-psql-posgtres';
ALTER ROLE
postgres=# alter user mastodon with password 'password-for-psql-mastodon';
ALTER ROLE
postgres=# \q
password-for-psql-***
の箇所はパスワード文字列なので取扱注意です。
(OS のユーザとは別物なので要注意)
Redis を Unix ドメインソケット通信に対応させる
まずは Redis 側の準備を。
# incoming connections. There is no default, so Redis will not listen
# on a unix socket when not specified.
#
-# unixsocket /run/redis.sock
-# unixsocketperm 700
+unixsocket /run/redis/redis.sock
+unixsocketperm 770
# Close the connection after a client is idle for N seconds (0 to disable)
timeout 0
# systemctl restart redis
# ls -lF /run/redis/
合計 0
srwxrwx---. 1 redis redis 0 2月 13 02:40 redis.sock=
Perl モジュールを導入する
これをやっておかないと、次の Ruby 導入時にコケる
# dnf install perl-FindBin perl-lib perl-File-Compare
Ruby を導入する
# su - mastodon
mastodon$ git clone https://github.com/rbenv/rbenv.git ~/.rbenv
mastodon$ cd ~/.rbenv && src/configure && make -C src
mastodon$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
mastodon$ echo 'eval "$(rbenv init -)"' >> ~/.bashrc
mastodon$ exit
# su - mastodon
mastodon$ git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
mastodon$ RUBY_CONFIGURE_OPTS=--with-jemalloc rbenv install 3.0.4
mastodon$ rbenv global 3.0.4
exit
して即入り直しているのは .bashrc
の適用のためです。
(source ~/.bashrc
や . ~/.bashrc
だと $PATH
がどんどん長くなるのが気に入らず…まぁ好みの問題ですが)
Bundler を導入する
mastodon$ gem install bundler --no-document
ドメイン関連の設定を行う
IP アドレスとドメイン名の関連付けを行う
各種サービスによって異なりますが、Value Domain の場合は概ね以下となります。
図のように、a subdomain 203.0.113.55
という A レコードの行を追加すると、IP アドレス 203.0.113.55
に対して subdomain.example.com
でアクセスできるようになります。
(example.com
でアクセスしたい場合は a @ 203.0.113.55
になります)
メールサーバの設定を行う
各種サービスによって異なりますが、今回は XREA でメールボックスを専用に割り当てました。
Mastodon を導入する
環境変数を設定する
最初に、環境変数 NODE_OPTIONS
を設定します。
mastodon$ echo "export NODE_OPTIONS='--openssl-legacy-provider --max-old-space-size=1536'" >> .bashrc
mastodon$ exit
# su - mastodon
-
--openssl-legacy-provider
を設定しておかないと、Mastodon ビルド時に OpenSSL 絡みでERR_OSSL_EVP_UNSUPPORTED
なるエラーを生じます。 -
--max-old-space-size=1536'"
を設定しておかないと、Mastodon ビルド時に Node.js のヒープ領域不足でエラーを生じます。
Mastodon ソースコードを取得する
mastodon$ git clone https://github.com/mastodon/mastodon.git live && cd live
mastodon$ git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)
依存性解決
mastodon$ bundle config deployment 'true'
mastodon$ bundle config without 'development test'
mastodon$ bundle install -j$(getconf _NPROCESSORS_ONLN)
mastodon$ yarn install --pure-lockfile
設定ファイルの生成
mastodon$ RAILS_ENV=production bundle exec rake mastodon:setup
Domain name: mstdn.yamachan.org
Do you want to enable single user mode? (y/N) n
Are you using Docker to run Mastodon? (Y/n) n
PostgreSQL host: (/var/run/postgresql) [そのまま Enter]
PostgreSQL port: (5432) [そのまま Enter]
Name of PostgreSQL database: (mastodon_production) [そのまま Enter]
Name of PostgreSQL user: (mastodon) [そのまま Enter]
Password of PostgreSQL user: password-for-psql-mastodon ★PostgreSQL ユーザ mastodon のパスワード。入力しても表示されない
Redis host: (localhost) [そのまま Enter]
Redis port: (6379) [そのまま Enter]
Redis password: [そのまま Enter]
Do you want to store uploaded files on the cloud? (y/N) n
Do you want to send e-mails from localhost? (y/N) n
SMTP server: (smtp.mailgun.org) s???.xrea.com ★XREA の契約サーバ名
SMTP port: (587) [そのまま Enter]
SMTP username: ?????@yamachan.org ★専用に割り当てたメールボックスのアカウント名
SMTP password: *** ★メールボックスのパスワード。入力しても表示されない
SMTP authentication: (plain) [そのまま Enter]
SMTP OpenSSL verify mode: none [そのまま Enter]
Enable STARTTLS: auto [そのまま Enter]
E-mail address to send e-mails "from": (...) *****@yamachan.org ★メールボックスと同じドメイン名にすること!デフォルトの "notifications@mstdn.yamachan.org" だとエラーになる。"@" より左側は違ってても大丈夫。
Send a test e-mail with this configuration right now? (Y/n) y
Send test e-mail to: (お好きなメールアドレスを入力)
Save configuration? (Y/n) y
Prepare the database now? (Y/n) y
Compile the assets now? (Y/n) y
Do you want to create an admin user straight away? (Y/n) y
Username: (admin) [そのまま Enter]
E-mail: *****@yamachan.org
最後に、You can login with the password: 115e44f01e7a...96bc
のような表示が出ます。
Mastodon の管理ユーザの初期パスワードなので、メモっておきます。
設定ファイルに追加設定
Redis への接続を Unix ドメインソケット化します。
DB_NAME=mastodon_production
DB_USER=mastodon
DB_PASS=password-for-psql-mastodon
-REDIS_HOST=localhost
-REDIS_PORT=6379
+#REDIS_HOST=localhost
+#REDIS_PORT=6379
+REDIS_URL=unix:///var/run/redis/redis.sock
REDIS_PASSWORD=
SMTP_SERVER=s???.xrea.com
SMTP_PORT=587
パスワード文字列が入っているので、パーミッションを固めておきます。
mastodon$ chmod 0600 .env.production
SELinux の設定を行う
※これをしないと、後ほど Mastodon を動かす際に bundle がエラーになります。
root に戻ります。
mastodon$ exit
以下を実行します。
# setsebool -P httpd_can_network_connect 1
# setsebool -P httpd_enable_homedirs 1
# setsebool -P httpd_read_user_content 1
以下のようなテキストファイル my-mastodon-policy.te
を作成します。
module my-mastodon-policy 1.0;
require {
type user_home_t;
type init_t;
class file { execute execute_no_trans open read };
}
allow init_t user_home_t:file { execute execute_no_trans open read };
上記ファイルを用いて、以下のコマンドを実行します。
# checkmodule -M -m -o my-mastodon-policy.mod my-mastodon-policy.te
# semodule_package -o my-mastodon-policy.pp -m my-mastodon-policy.mod
# semodule -i my-mastodon-policy.pp
nginx の設定を行う (1/2)
起動ユーザを nginx
から mastodon
に変更します。
# * Official English Documentation: http://nginx.org/en/docs/
# * Official Russian Documentation: http://nginx.org/ru/docs/
-user nginx;
+user mastodon;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
sites-enabled
を有効にします。
# for more information.
include /etc/nginx/conf.d/*.conf;
+ # to enable virtual host
+ include /etc/nginx/sites-enabled/*;
+
server {
listen 80;
listen [::]:80;
ディレクトリを作成します。
# cd /etc/nginx
# mkdir sites-available
# mkdir sites-enabled
ログディレクトリを起動ユーザの所有に変更します。
(これをしないとログロテートが正常に働きませんでした)
# cd /var/log/nginx
# chown mastodon .
# chmod 0750 .
起動します。
# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
# systemctl start nginx
Let's Encrypt の設定を行う
まずは証明書を発行します。
# certbot certonly --nginx -d mstdn.yamachan.org
Enter email address: *****@yamachan.org
Please read the Terms of Service at ... Do you agree?
(Y)es/(N)o: y
... share your email address with the Electronic Frontier Foundation ... ?
(Y)es/(N)o: n
次に、一週間に一度自動更新するように cron.weekly にスクリプトを置きます。
#!/usr/bin/sh
/usr/bin/certbot renew --deploy-hook '/usr/bin/systemctl reload nginx' >> /root/lets_encrypt.log 2>&1
実行権限を付与します。
# chmod 0700 /etc/cron.weekly/lets_encrypt
Mastodon のサービス設定を行う
# cp /home/mastodon/live/dist/mastodon-*.service /etc/systemd/system/
# systemctl daemon-reload
# systemctl enable --now mastodon-web mastodon-sidekiq mastodon-streaming
nginx の設定を行う (2/2)
Mastodon のサイト設定をコピーします。
この時 example.com
を mstdn.yamachan.org
で置き換え、ssl_certificate
で始まる行を有効化します。
# sed 's/example.com/mstdn.yamachan.org/' /home/mastodon/live/dist/nginx.conf | sed 's/# ssl_certificate/ssl_certificate/' > /etc/nginx/sites-available/mastodon
シンボリックリンクを貼ります。
# ln -s /etc/nginx/sites-available/mastodon /etc/nginx/sites-enabled/mastodon
/var/lib/nginx
の所有者を mastodon
に変更します。
# chown -R mastodon /var/lib/nginx
起動時有効化した上で、デーモンを再起動します。
# systemctl enable nginx
# systemctl restart nginx
クリーンアップタスクを設定する
# su - mastodon
mastodon$ echo $PATH
/home/mastodon/.rbenv/shims:/home/mastodon/.rbenv/bin:/home/mastodon/.local/bin:/home/mastodon/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin
# crontab -e
下記のように、echo $PATH
で調べた内容を先頭に PATH=
として書きます。
更に公式に記載のあるコマンド 2 行を追記します (@weekly
は 0 0 * * 0
になるそうなので、敢えて時間をずらしました)。
PATH=/home/mastodon/.rbenv/shims:/home/mastodon/.rbenv/bin:/home/mastodon/.local/bin:/home/mastodon/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin
4 4 * * 0 RAILS_ENV=production /home/mastodon/live/bin/tootctl media remove
24 4 * * 0 RAILS_ENV=production /home/mastodon/live/bin/tootctl preview_cards remove
参考にさせていただいたページ